From e61342ea3ba2efd602da04b2362421f4f4b8486e Mon Sep 17 00:00:00 2001 From: ieow Date: Fri, 7 Feb 2025 19:51:19 +0800 Subject: [PATCH 01/16] feat: initial commit integrate multicurve tkey tests passed --- package-lock.json | 201 +++++++++++++++---------------- package.json | 10 +- src/interfaces.ts | 9 ++ src/mpcCoreKit.ts | 190 ++++++++++++++++++++--------- tests/backwardCompatible.spec.ts | 5 +- tests/bip340.spec.ts | 17 ++- tests/ed25519.spec.ts | 18 +-- tests/factors.spec.ts | 5 +- tests/importRecovery.spec.ts | 3 +- tests/login.spec.ts | 10 +- tests/securityQuestion.spec.ts | 10 +- tests/sessionTime.spec.ts | 2 + tests/setup.ts | 12 +- 13 files changed, 282 insertions(+), 210 deletions(-) diff --git a/package-lock.json b/package-lock.json index d2fa201f..660ddb6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,11 @@ "version": "4.1.7-alpha.0", "license": "ISC", "dependencies": { - "@tkey/common-types": "^15.1.0", - "@tkey/core": "^15.1.0", + "@tkey/common-types": "file:../tkey/packages/common-types", + "@tkey/core": "file:../tkey/packages/core/tkey-core-15.2.1-alpha.0.tgz", "@tkey/share-serialization": "^15.1.0", - "@tkey/storage-layer-torus": "^15.1.0", - "@tkey/tss": "^15.1.0", + "@tkey/storage-layer-torus": "file:../tkey/packages/storage-layer-torus/tkey-storage-layer-torus-15.2.1-alpha.0.tgz", + "@tkey/tss": "file:../tkey/packages/tss/tkey-tss-15.2.1-alpha.0.tgz", "@toruslabs/constants": "^14.2.0", "@toruslabs/customauth": "^20.3.0", "@toruslabs/elliptic-wrapper": "^0.1.1", @@ -84,6 +84,30 @@ } } }, + "../tkey/packages/common-types": { + "name": "@tkey/common-types", + "version": "15.2.1-alpha.0", + "license": "MIT", + "dependencies": { + "@toruslabs/customauth": "^20.3.0", + "@toruslabs/eccrypto": "^5.0.4", + "@toruslabs/torus.js": "^15.1.0", + "bn.js": "^5.2.1", + "elliptic": "^6.5.5", + "ts-custom-error": "^3.3.1" + }, + "devDependencies": { + "@types/bn.js": "^5.1.5", + "@types/elliptic": "^6.4.18" + }, + "engines": { + "node": ">=18.x", + "npm": ">=9.x" + }, + "peerDependencies": { + "@babel/runtime": "7.x" + } + }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", @@ -3754,17 +3778,23 @@ } }, "node_modules/@tkey/common-types": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@tkey/common-types/-/common-types-15.1.0.tgz", - "integrity": "sha512-oA5gLoyhNNMgCKcjvwLyU31TVS5KMT+lotRrjjoBdDvS0keZwzSLrtHWbXj8jZDlSZaqbd3VlPbCoHcqpk1irA==", + "resolved": "../tkey/packages/common-types", + "link": true + }, + "node_modules/@tkey/core": { + "version": "15.2.1-alpha.0", + "resolved": "file:../tkey/packages/core/tkey-core-15.2.1-alpha.0.tgz", + "integrity": "sha512-oR27rVrBUjhhABEsnclpa/z13C7jAl/QTkBthivDgnGCC8+CQ59uEaiBrD3LmVmrkwBJ31+y4g7cqJJJc0Wz7g==", "license": "MIT", "dependencies": { - "@toruslabs/customauth": "^20.3.0", + "@tkey/common-types": "^15.2.1-alpha.0", "@toruslabs/eccrypto": "^5.0.4", + "@toruslabs/http-helpers": "^7.0.0", "@toruslabs/torus.js": "^15.1.0", "bn.js": "^5.2.1", "elliptic": "^6.5.5", - "ts-custom-error": "^3.3.1" + "ethereum-cryptography": "^2.1.3", + "json-stable-stringify": "^1.1.1" }, "engines": { "node": ">=18.x", @@ -3774,7 +3804,7 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey/common-types/node_modules/@toruslabs/torus.js": { + "node_modules/@tkey/core/node_modules/@toruslabs/torus.js": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/@toruslabs/torus.js/-/torus.js-15.1.1.tgz", "integrity": "sha512-sLaXA1/R8KTTjU4t+teL3PPaJr2+j01QLYn5IY/t5uTD+1G2nzzfVWpkMDYrk9EfQYw0u4aKJ1lT7j9uKafMlg==", @@ -3798,20 +3828,36 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey/core": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@tkey/core/-/core-15.1.0.tgz", - "integrity": "sha512-JaFprczHR8fBEw1LrwKs87ASgpZagxQ9VZ6lAfAAI8jEh1yhz8djh9l2wzJbaFuLEOQskh7GoxpKfgB+YtBSmw==", + "node_modules/@tkey/service-provider-base": { + "version": "15.2.1-alpha.0", + "resolved": "https://registry.npmjs.org/@tkey/service-provider-base/-/service-provider-base-15.2.1-alpha.0.tgz", + "integrity": "sha512-8CTHuAoglCfDhxk3U0VkWJTl6XcL5UXIQAjtRTo/fbFClsHZ1lfQREXe24m+185XwBsZySrgE+UpL/Qvrq9vow==", "license": "MIT", "dependencies": { - "@tkey/common-types": "^15.1.0", - "@toruslabs/eccrypto": "^5.0.4", - "@toruslabs/http-helpers": "^7.0.0", + "@tkey/common-types": "^15.2.1-alpha.0", + "bn.js": "^5.2.1", + "elliptic": "^6.5.5" + }, + "engines": { + "node": ">=18.x", + "npm": ">=9.x" + }, + "peerDependencies": { + "@babel/runtime": "7.x" + } + }, + "node_modules/@tkey/service-provider-torus": { + "version": "15.2.1-alpha.0", + "resolved": "https://registry.npmjs.org/@tkey/service-provider-torus/-/service-provider-torus-15.2.1-alpha.0.tgz", + "integrity": "sha512-ZkVaZvf0S+wrjN7nVAwq87+X02XJSCal2aCEYoRtoYQAcqp0wgTMPzBB6r4Jo1VyWIYbXS9zl6fZ90h1I86YVQ==", + "license": "MIT", + "dependencies": { + "@tkey/common-types": "^15.2.1-alpha.0", + "@tkey/service-provider-base": "^15.2.1-alpha.0", + "@toruslabs/customauth": "^20.3.0", "@toruslabs/torus.js": "^15.1.0", "bn.js": "^5.2.1", - "elliptic": "^6.5.5", - "ethereum-cryptography": "^2.1.3", - "json-stable-stringify": "^1.1.1" + "elliptic": "^6.5.5" }, "engines": { "node": ">=18.x", @@ -3821,7 +3867,7 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey/core/node_modules/@toruslabs/torus.js": { + "node_modules/@tkey/service-provider-torus/node_modules/@toruslabs/torus.js": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/@toruslabs/torus.js/-/torus.js-15.1.1.tgz", "integrity": "sha512-sLaXA1/R8KTTjU4t+teL3PPaJr2+j01QLYn5IY/t5uTD+1G2nzzfVWpkMDYrk9EfQYw0u4aKJ1lT7j9uKafMlg==", @@ -3845,15 +3891,15 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey/service-provider-base": { + "node_modules/@tkey/share-serialization": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@tkey/service-provider-base/-/service-provider-base-15.1.0.tgz", - "integrity": "sha512-MruUxiWwyRczZ8KlhhGJ2TQ/p+VFPMOQZ089B5SIi7UsTOBMlzRqJWP3lM2fBSyQsfJCzpzXkj9a29ecpRZe0g==", + "resolved": "https://registry.npmjs.org/@tkey/share-serialization/-/share-serialization-15.1.0.tgz", + "integrity": "sha512-n8jf6WDAWcWKFUr/nSnBURxX8vlXCQjJOfQUchiqvvUFlExeDqXqJq8I5icn2hjxKqANNcXVf1vKSvOCxPCAng==", "license": "MIT", "dependencies": { "@tkey/common-types": "^15.1.0", "bn.js": "^5.2.1", - "elliptic": "^6.5.5" + "ethereum-cryptography": "^2.2.1" }, "engines": { "node": ">=18.x", @@ -3863,18 +3909,18 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey/service-provider-torus": { + "node_modules/@tkey/share-serialization/node_modules/@tkey/common-types": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@tkey/service-provider-torus/-/service-provider-torus-15.1.0.tgz", - "integrity": "sha512-7tA/1ALPo4ToXvwTwMj9OF0wh97S3p1sCeilwRcfyxBMJGpaDW8MSbiAbPqaSkK/DT3AFxlkHwAXWYYZ4+ZueQ==", + "resolved": "https://registry.npmjs.org/@tkey/common-types/-/common-types-15.1.0.tgz", + "integrity": "sha512-oA5gLoyhNNMgCKcjvwLyU31TVS5KMT+lotRrjjoBdDvS0keZwzSLrtHWbXj8jZDlSZaqbd3VlPbCoHcqpk1irA==", "license": "MIT", "dependencies": { - "@tkey/common-types": "^15.1.0", - "@tkey/service-provider-base": "^15.1.0", "@toruslabs/customauth": "^20.3.0", + "@toruslabs/eccrypto": "^5.0.4", "@toruslabs/torus.js": "^15.1.0", "bn.js": "^5.2.1", - "elliptic": "^6.5.5" + "elliptic": "^6.5.5", + "ts-custom-error": "^3.3.1" }, "engines": { "node": ">=18.x", @@ -3884,7 +3930,7 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey/service-provider-torus/node_modules/@toruslabs/torus.js": { + "node_modules/@tkey/share-serialization/node_modules/@toruslabs/torus.js": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/@toruslabs/torus.js/-/torus.js-15.1.1.tgz", "integrity": "sha512-sLaXA1/R8KTTjU4t+teL3PPaJr2+j01QLYn5IY/t5uTD+1G2nzzfVWpkMDYrk9EfQYw0u4aKJ1lT7j9uKafMlg==", @@ -3908,31 +3954,13 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey/share-serialization": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@tkey/share-serialization/-/share-serialization-15.1.0.tgz", - "integrity": "sha512-n8jf6WDAWcWKFUr/nSnBURxX8vlXCQjJOfQUchiqvvUFlExeDqXqJq8I5icn2hjxKqANNcXVf1vKSvOCxPCAng==", - "license": "MIT", - "dependencies": { - "@tkey/common-types": "^15.1.0", - "bn.js": "^5.2.1", - "ethereum-cryptography": "^2.2.1" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, "node_modules/@tkey/storage-layer-torus": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@tkey/storage-layer-torus/-/storage-layer-torus-15.1.0.tgz", - "integrity": "sha512-ZRk1FclOEomd7KAE3evKc/4Nk9I//RW20Bq2UrSPyKGf5YeTbDTaglAK0GrcG5CPtCpVLqh348Bw6hvGzjArag==", + "version": "15.2.1-alpha.0", + "resolved": "file:../tkey/packages/storage-layer-torus/tkey-storage-layer-torus-15.2.1-alpha.0.tgz", + "integrity": "sha512-5f3N6JoAFAqEGoEm/Qpuc5+ncxnXsuZMCCAjV4yokBJHVEbFLcYnW5LPWqbnWULavGMDHjnfpy49bBR/5UG3Uw==", "license": "MIT", "dependencies": { - "@tkey/common-types": "^15.1.0", + "@tkey/common-types": "^15.2.1-alpha.0", "@toruslabs/http-helpers": "^7.0.0", "base64url": "3.0.1", "bn.js": "^5.2.1", @@ -3948,17 +3976,18 @@ } }, "node_modules/@tkey/tss": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@tkey/tss/-/tss-15.1.0.tgz", - "integrity": "sha512-UcbJbWscIL83Zh1/i6M+X/xhN4EOimGV8JoWZ3D23Ji2pHPo8BgveUZA9i1DK4Y3YqqZ9aS8PvhSHt+KVnNluw==", + "version": "15.2.1-alpha.0", + "resolved": "file:../tkey/packages/tss/tkey-tss-15.2.1-alpha.0.tgz", + "integrity": "sha512-KncB4Ws/+Sj0dy/3fh+0dv299E9i7Rrkf4VeYeeV0D5ErlqCze8SWXoX9eQXdUgdF0ryxUHNLckjg6ljCcmXMg==", "license": "ISC", "dependencies": { - "@tkey/common-types": "^15.1.0", - "@tkey/core": "^15.1.0", - "@tkey/service-provider-torus": "^15.1.0", + "@tkey/common-types": "^15.2.1-alpha.0", + "@tkey/core": "^15.2.1-alpha.0", + "@tkey/service-provider-torus": "^15.2.1-alpha.0", "@toruslabs/customauth": "^20.3.0", + "@toruslabs/http-helpers": "^7.0.0", "@toruslabs/rss-client": "^2.0.1", - "@toruslabs/torus.js": "^15.1.0", + "@toruslabs/torus.js": "file:../../../torus.js/toruslabs-torus.js-15.1.1.tgz", "@types/bn.js": "^5.1.5", "bn.js": "^5.2.1", "elliptic": "^6.5.5", @@ -3967,8 +3996,8 @@ }, "node_modules/@tkey/tss/node_modules/@toruslabs/torus.js": { "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@toruslabs/torus.js/-/torus.js-15.1.1.tgz", - "integrity": "sha512-sLaXA1/R8KTTjU4t+teL3PPaJr2+j01QLYn5IY/t5uTD+1G2nzzfVWpkMDYrk9EfQYw0u4aKJ1lT7j9uKafMlg==", + "resolved": "file:../torus.js/toruslabs-torus.js-15.1.1.tgz", + "integrity": "sha512-kkLuZ9vpmWZTklva+RQFKozDMCR2ydhR5WBn9bbgJBZqVP75FSzLZL0LQYrFqBPMgKgV22uOQ8quXW6T+Kko/g==", "license": "MIT", "dependencies": { "@toruslabs/bs58": "^1.0.0", @@ -4515,16 +4544,15 @@ } }, "node_modules/@toruslabs/rss-client": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@toruslabs/rss-client/-/rss-client-2.0.1.tgz", - "integrity": "sha512-EBqAX7LK8ZBy4fiGTGQhI3wVvLvfUyfwREbNkfAxP/iwevgCA2EKLXGWtVsvJj/wXF8HkfjqOcorVeHwP2vvWw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@toruslabs/rss-client/-/rss-client-2.0.2.tgz", + "integrity": "sha512-kmtl7KaxTOdrftxtv/hTzz6k2RJbVFq6oPs5Vg4u4iybdQYdRzyP1HqQ3wMu9ADhiItbZAg80VP4gOCCmjao4w==", "license": "MIT", "dependencies": { "@toruslabs/eccrypto": "^5.0.4", "@toruslabs/http-helpers": "^7.0.0", "bn.js": "^5.2.1", "elliptic": "^6.5.7", - "fetch": "^1.1.0", "loglevel": "^1.9.2" }, "engines": { @@ -6236,18 +6264,6 @@ "@noble/hashes": "^1.2.0" } }, - "node_modules/biskviit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/biskviit/-/biskviit-1.0.1.tgz", - "integrity": "sha512-VGCXdHbdbpEkFgtjkeoBN8vRlbj1ZRX2/mxhE8asCCRalUx2nBzOomLJv8Aw/nRt5+ccDb+tPKidg4XxcfGW4w==", - "license": "MIT", - "dependencies": { - "psl": "^1.1.7" - }, - "engines": { - "node": ">=1.0.0" - } - }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -7858,15 +7874,6 @@ "typedarray-to-buffer": "3.1.5" } }, - "node_modules/encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha512-bl1LAgiQc4ZWr++pNYUdRe/alecaHFeHxIJ/pNciqGdKXghaTCOwKkbKp6ye7pKZGu/GcaSXFk8PBVhgs+dJdA==", - "license": "MIT", - "dependencies": { - "iconv-lite": "~0.4.13" - } - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -9138,16 +9145,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-5O8TwrGzoNblBG/jtK4NFuZwNCkZX6s5GfRNOaGtm+QGJEuNakSC/i2RW0R93KX6E0jVjNXm6O3CRN4Ql3K+yA==", - "license": "MIT", - "dependencies": { - "biskviit": "1.0.1", - "encoding": "0.1.12" - } - }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -10185,6 +10182,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" @@ -13717,12 +13715,6 @@ "dev": true, "license": "MIT" }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "license": "MIT" - }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -14818,6 +14810,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, "license": "MIT" }, "node_modules/schema-utils": { diff --git a/package.json b/package.json index 15a15e16..b150dc06 100644 --- a/package.json +++ b/package.json @@ -47,11 +47,11 @@ } }, "dependencies": { - "@tkey/common-types": "^15.1.0", - "@tkey/core": "^15.1.0", + "@tkey/common-types": "file:../tkey/packages/common-types", + "@tkey/core": "file:../tkey/packages/core/tkey-core-15.2.1-alpha.0.tgz", "@tkey/share-serialization": "^15.1.0", - "@tkey/storage-layer-torus": "^15.1.0", - "@tkey/tss": "^15.1.0", + "@tkey/storage-layer-torus": "file:../tkey/packages/storage-layer-torus/tkey-storage-layer-torus-15.2.1-alpha.0.tgz", + "@tkey/tss": "file:../tkey/packages/tss/tkey-tss-15.2.1-alpha.0.tgz", "@toruslabs/constants": "^14.2.0", "@toruslabs/customauth": "^20.3.0", "@toruslabs/elliptic-wrapper": "^0.1.1", @@ -59,8 +59,8 @@ "@toruslabs/fnd-base": "^14.2.0", "@toruslabs/metadata-helpers": "^6.0.0", "@toruslabs/openlogin-utils": "^8.2.1", - "@toruslabs/torus.js": "15.2.0-alpha.0", "@toruslabs/session-manager": "^3.1.0", + "@toruslabs/torus.js": "15.2.0-alpha.0", "@toruslabs/tss-client": "^3.3.0-alpha.0", "@toruslabs/tss-frost-client": "^1.0.1-alpha.0", "@toruslabs/tss-frost-common": "^1.0.2-alpha.0", diff --git a/src/interfaces.ts b/src/interfaces.ts index ccfb484d..3b19cb64 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -333,6 +333,15 @@ export interface Web3AuthOptions { * only scalar will be exported, scalar can be used for signing outside of this sdk but not for importing the key in other wallets. */ useClientGeneratedTSSKey?: boolean; + + /** + * @defaultValue `false` + * Set this flag to true to use the legacy flag for signing + * legacy flag do not support multicurve mode + * legacy ed25519 customAuth is only supported in legacy mode + * Note: This option is set to false by default. + */ + legacyFlag?: boolean; } export type Web3AuthOptionsWithDefaults = Required; diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 44b7fc1d..dddf41f3 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -2,7 +2,7 @@ import { BNString, KeyType, ONE_KEY_DELETE_NONCE, Point, secp256k1, SHARE_DELETE import { CoreError } from "@tkey/core"; import { ShareSerializationModule } from "@tkey/share-serialization"; import { TorusStorageLayer } from "@tkey/storage-layer-torus"; -import { factorKeyCurve, getPubKeyPoint, lagrangeInterpolation, TKeyTSS, TSSTorusServiceProvider } from "@tkey/tss"; +import { factorKeyCurve, getPubKeyPoint, lagrangeInterpolation, TKeyTSS, TSS_TAG_DEFAULT, TSSTorusServiceProvider } from "@tkey/tss"; import { SIGNER_MAP } from "@toruslabs/constants"; import { AGGREGATE_VERIFIER, TORUS_METHOD, TorusAggregateLoginResponse, TorusLoginResponse, UX_MODE } from "@toruslabs/customauth"; import type { UX_MODE_TYPE } from "@toruslabs/customauth/dist/types/utils/enums"; @@ -10,7 +10,7 @@ import { Ed25519Curve, Secp256k1Curve } from "@toruslabs/elliptic-wrapper"; import { fetchLocalConfig } from "@toruslabs/fnd-base"; import { keccak256 } from "@toruslabs/metadata-helpers"; import { SessionManager } from "@toruslabs/session-manager"; -import { Torus as TorusUtils, TorusKey } from "@toruslabs/torus.js"; +import { getKeyCurve, Torus as TorusUtils, TorusKey } from "@toruslabs/torus.js"; import { Client, getDKLSCoeff, setupSockets } from "@toruslabs/tss-client"; import type { WasmLib as DKLSWasmLib } from "@toruslabs/tss-dkls-lib"; import { sign as signFrost } from "@toruslabs/tss-frost-client"; @@ -136,6 +136,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!options.disableHashedFactorKey) options.disableHashedFactorKey = false; if (!options.hashedFactorNonce) options.hashedFactorNonce = options.web3AuthClientId; if (options.disableSessionManager === undefined) options.disableSessionManager = false; + if (!options.legacyFlag) options.legacyFlag = false; + this.sessionSigGenerator = new DefaultSessionSigGeneratorPlugin(this); this.options = options as Web3AuthOptionsWithDefaults; @@ -221,6 +223,27 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return this.sessionSigGenerator.getSessionSigs(); } + public setTkeyType(tkeyType: KeyType) { + // check tkeyType is supported by tssLib + this._keyType = tkeyType; + } + + public getTssShare(factorkey: BN, accountIndex?: number) { + return this.tkey.getTSSShare(factorkey, { + tssTag: TSS_TAG_DEFAULT, + keyType: this.keyType, + accountIndex: accountIndex === undefined ? this.state.accountIndex : accountIndex, + }); + } + + public getTssData(args: { skipThrow: boolean } = { skipThrow: false }) { + const result = this.tkey.metadata.getTssData(this.keyType, TSS_TAG_DEFAULT); + if (!result && !args.skipThrow) { + throw CoreKitError.noMetadataFound(); + } + return result; + } + // RecoverTssKey only valid for user that enable MFA where user has 2 type shares : // TssShareType.DEVICE and TssShareType.RECOVERY // if the factors key provided is the same type recovery will not works @@ -234,7 +257,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const tssIndexesBN: BN[] = []; for (let i = 0; i < factorKey.length; i++) { const factorKeyBNInput = new BN(factorKey[i], "hex"); - const { tssIndex, tssShare } = await this.tKey.getTSSShare(factorKeyBNInput); + const { tssIndex, tssShare } = await this.getTssShare(factorKeyBNInput); if (tssIndexes.includes(tssIndex)) { // reset instance before throw error await this.init(); @@ -245,7 +268,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { tssShares.push(tssShare); } - const finalKey = lagrangeInterpolation(this.tkey.tssCurve, tssShares, tssIndexesBN); + const tssCurve = getKeyCurve(this.keyType); + const finalKey = lagrangeInterpolation(tssCurve, tssShares, tssIndexesBN); // reset instance after recovery completed await this.init(); return finalKey.toString("hex", 64); @@ -261,6 +285,14 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.invalidConfig("DKG is not supported for ed25519 signature type"); } + // multicurve only support for secp256k1 torus/ sss + let keyType = KeyType.secp256k1; + if (this.options.legacyFlag) { + // check for added supported keyType + // if keyType is ed25519, + keyType = this.keyType; + } + this.torusSp = new TSSTorusServiceProvider({ customAuthArgs: { web3AuthClientId: this.options.web3AuthClientId, @@ -270,7 +302,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { redirectPathName: this.options.redirectPathName, locationReplaceOnRedirect: true, serverTimeOffset: this.options.serverTimeOffset, - keyType: this.keyType, + keyType, useDkg: this.options.useDKG, }, }); @@ -290,7 +322,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { modules: { shareSerialization: shareSerializationModule, }, - tssKeyType: this.keyType, + legacyMetadataFlag: this.options.legacyFlag, }); if (this.isRedirectMode) { @@ -424,7 +456,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { // prefetch tss pub keys. const prefetchTssPubs = []; for (let i = 0; i < prefetchTssPublicKeys; i++) { - prefetchTssPubs.push(this.torusSp.getTSSPubKey(this.tkey.tssTag, i)); + prefetchTssPubs.push(this.torusSp.getTSSPubKey(this.tkey.tssTag, i, this.keyType)); } // get postbox key. @@ -546,7 +578,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } public setTssWalletIndex(accountIndex: number) { - this.updateState({ tssPubKey: this.tKey.getTSSPub(accountIndex).toSEC1(this.tkey.tssCurve, false), accountIndex }); + this.updateState({ tssPubKey: this.getPubKey(false, accountIndex), accountIndex }); } public getCurrentFactorKey(): IFactorKey { @@ -628,7 +660,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when getting tss factor public key."); } - const factorPubsList = this.tKey.metadata.factorPubs[this.tKey.tssTag]; + const tssData = this.getTssData(); + const factorPubsList = tssData.factorPubs; return factorPubsList.map((factorPub) => factorPub.toSEC1(factorKeyCurve, true).toString("hex")); }; @@ -675,17 +708,18 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { /** * Get public key point in SEC1 format. */ - public getPubKey(): Buffer { - const { tssPubKey } = this.state; - return Buffer.from(tssPubKey); + public getPubKey(compressed: boolean = true, accountIndex?: number): Buffer { + const tssPubKey = this.getPubKeyPoint(accountIndex); + const tssCurve = getKeyCurve(this.keyType); + return tssPubKey.toSEC1(tssCurve, compressed); } /** * Get public key point. */ - public getPubKeyPoint(): Point { - const { tssPubKey } = this.state; - return Point.fromSEC1(this.tkey.tssCurve, tssPubKey.toString("hex")); + public getPubKeyPoint(accountIndex?: number): Point { + const tssPubKey = this.tkey.getTSSPub(this.keyType, TSS_TAG_DEFAULT, accountIndex === undefined ? this.state.accountIndex : accountIndex); + return tssPubKey; } /** @@ -698,7 +732,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.default(`getPubKeyEd25519 not supported for signature type ${this.sigType}`); } - const p = this.tkey.tssCurve.keyFromPublic(this.getPubKey()).getPublic(); + const tssCurve = getKeyCurve(this.keyType); + const p = this.getPubKeyPoint().toEllipticPoint(tssCurve); return ed25519().keyFromPublic(p).getPublic(); } @@ -712,7 +747,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.default(`getPubKeyBip340 not supported for signature type ${this.sigType}`); } - const p = this.tkey.tssCurve.keyFromPublic(this.getPubKey()).getPublic(); + const tssCurve = getKeyCurve(this.keyType); + const p = this.getPubKeyPoint().toEllipticPoint(tssCurve); return p.getX().toBuffer("be", 32); } @@ -732,9 +768,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when signing."); } - const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey, { - accountIndex: 0, - }); + const { tssShare } = await this.getTssShare(this.state.factorKey, 0); const tssNonce = this.getTssNonce(); if (!tssPubKey || !torusNodeTSSEndpoints) { @@ -749,7 +783,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const clientIndex = parties - 1; // 1. setup // generate endpoints for servers - const { nodeIndexes } = await this.torusSp.getTSSPubKey(this.tKey.tssTag, this.tKey.metadata.tssNonces[this.tKey.tssTag]); + const tssData = this.getTssData(); + const { nodeIndexes } = await this.torusSp.getTSSPubKey(this.tKey.tssTag, tssData.tssNonce, this.keyType); const { endpoints, tssWSEndpoints, @@ -846,12 +881,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when deleting a factor."); } - if (!this.tKey.metadata.factorPubs) { + const tssData = this.getTssData(); + if (!tssData.factorPubs) { throw CoreKitError.factorPubsMissing(); } await this.atomicSync(async () => { - const remainingFactors = this.tKey.metadata.factorPubs[this.tKey.tssTag].length || 0; + const remainingFactors = tssData.factorPubs.length || 0; if (remainingFactors <= 1) { throw CoreKitError.cannotDeleteLastFactor("Cannot delete last factor"); } @@ -862,9 +898,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } const authSignatures = await this.getSessionSignatures(); - await this.tKey.deleteFactorPub({ factorKey: this.state.factorKey, deleteFactorPub: factorPub, authSignatures }); + await this.tKey.deleteFactorPub({ factorKey: this.state.factorKey, deleteFactorPub: factorPub, authSignatures, tssTag: TSS_TAG_DEFAULT }); const factorPubHex = fpp.toSEC1(factorKeyCurve, true).toString("hex"); - const allDesc = this.tKey.metadata.getShareDescription(); + const allDesc = this.tkey.metadata.getShareDescription(); const keyDesc = allDesc[factorPubHex]; if (keyDesc) { await Promise.all(keyDesc.map(async (desc) => this.tKey?.metadata.deleteShareDescription(factorPubHex, desc))); @@ -903,10 +939,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { public getKeyDetails(): MPCKeyDetails { this.checkReady(); + const tssData = this.getTssData({ skipThrow: true }); const tkeyDetails = this.tKey.getKeyDetails(); - const tssPubKey = this.state.tssPubKey ? Point.fromSEC1(this.tkey.tssCurve, this.state.tssPubKey.toString("hex")) : undefined; + const tssCurve = getKeyCurve(this.keyType); + // TODO: fix me, should remove tssPubKey from state + const tssPubKey = this.state.tssPubKey ? Point.fromSEC1(tssCurve, this.state.tssPubKey.toString("hex")) : undefined; - const factors = this.tKey.metadata.factorPubs ? this.tKey.metadata.factorPubs[this.tKey.tssTag] : []; + const factors = tssData?.factorPubs ? tssData.factorPubs : []; const keyDetails: MPCKeyDetails = { // use tkey's for now requiredFactors: tkeyDetails.requiredShares, @@ -992,10 +1031,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const exportTssKey0 = await this.tKey._UNSAFE_exportTssKey({ factorKey: this.state.factorKey, authSignatures: this.state.signatures, + keyType: this.keyType, + tssTag: TSS_TAG_DEFAULT, }); const accountNonce = this.getAccountNonce(); - const tssKey = exportTssKey0.add(accountNonce).umod(this.tKey.tssCurve.n); + const tssCurve = getKeyCurve(this.keyType); + const tssKey = exportTssKey0.add(accountNonce).umod(tssCurve.n); return tssKey.toString("hex", FIELD_ELEMENT_HEX_LEN); } @@ -1017,6 +1059,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const exportEd25519Seed = await this.tKey._UNSAFE_exportTssEd25519Seed({ factorKey: this.state.factorKey, authSignatures: this.state.signatures, + tssTag: TSS_TAG_DEFAULT, }); return exportEd25519Seed; @@ -1107,22 +1150,24 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } } - private async importTssKey(tssKey: string, factorPub: Point, newTSSIndex: TssShareType = TssShareType.DEVICE): Promise { - if (!this.state.signatures) { - throw CoreKitError.signaturesNotPresent("Signatures not present in state when importing tss key."); - } + // private async importTssKey(tssKey: string, factorPub: Point, newTSSIndex: TssShareType = TssShareType.DEVICE): Promise { + // if (!this.state.signatures) { + // throw CoreKitError.signaturesNotPresent("Signatures not present in state when importing tss key."); + // } - await this.tKey.importTssKey( - { tag: this.tKey.tssTag, importKey: Buffer.from(tssKey, "hex"), factorPub, newTSSIndex }, - { authSignatures: this.state.signatures } - ); - } + // const keyType = this._keyType + // await this.tKey.importTssKey( + // { tssTag: this.tKey.tssTag, importKey: Buffer.from(tssKey, "hex"), factorPubs: [factorPub], newTSSIndexes: [newTSSIndex], tssKeyType: keyType }, + // { authSignatures: this.state.signatures } + // ); + // } private getTssNonce(): number { - if (!this.tKey.metadata.tssNonces || this.tKey.metadata.tssNonces[this.tKey.tssTag] === undefined) { + const tssData = this.getTssData(); + if (tssData.tssNonce === undefined) { throw CoreKitError.tssNoncesMissing(`tssNonce not present for tag ${this.tKey.tssTag}`); } - const tssNonce = this.tKey.metadata.tssNonces[this.tKey.tssTag]; + const { tssNonce } = tssData; return tssNonce; } @@ -1141,15 +1186,37 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } const deviceTSSIndex = TssShareType.DEVICE; const factorPub = getPubKeyPoint(factorKey, factorKeyCurve); - if (!importTssKey) { - const ec = new EC(this.keyType); - const deviceTSSShare = ec.genKeyPair().getPrivate(); - await this.tKey.initialize({ factorPub, deviceTSSShare, deviceTSSIndex }); - } else { - await this.tKey.initialize({ skipTssInit: true }); - await this.tKey.reconstructKey(); - await this.importTssKey(importTssKey, factorPub, deviceTSSIndex); - } + + const ec = new EC(this.keyType); + const deviceTSSShare = ec.genKeyPair().getPrivate(); + await this.tKey.initialize(); + + // if both keyType library is avaiable, initialize secp256k1 first as secp256k1 is initialize offline + + // check if key is in the tsslib and keytype exists + await this.tKey.initializeTss({ + importKey: importTssKey ? Buffer.from(importTssKey, "hex") : undefined, + factorPub, + deviceTSSShare, + deviceTSSIndex, + tssKeyType: this._keyType, + serverOpts: { + // selectedServers: [], + authSignatures: this.state.signatures, + }, + }); + + //TODO resolve this + // if both key type available + // if () { + // await this.tKey.initializeTss({ + // importKey: importTssKey? Buffer.from(importTssKey) : undefined, tssKeyType: this._keyType, + // serverOpts: { + // // selectedServers: [], + // authSignatures: this.state.signatures + // } + // }); + // } // Finalize initialization. await this.tKey.reconstructKey(); @@ -1212,8 +1279,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { this.state.accountIndex = 0; } // Read tss meta data. - const { tssIndex: tssShareIndex } = await this.tKey.getTSSShare(factorKey); - const tssPubKey = this.tKey.getTSSPub().toSEC1(this.tkey.tssCurve, false); + const { tssIndex: tssShareIndex } = await this.getTssShare(factorKey); + const tssCurve = getKeyCurve(this._keyType); + const tssPubKey = this.tKey.getTSSPub(this.keyType, TSS_TAG_DEFAULT).toSEC1(tssCurve, false); this.updateState({ tssShareIndex, tssPubKey, factorKey }); @@ -1246,12 +1314,16 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { await this.tKey.inputShareStoreSafe(factorKeyMetadata, true); await this.tKey.reconstructKey(); + const tssCurve = getKeyCurve(this._keyType); + this.updateState({ factorKey: new BN(result.factorKey, "hex"), postBoxKey, postboxKeyNodeIndexes: result.postboxKeyNodeIndexes || [], tssShareIndex: result.tssShareIndex, - tssPubKey: this.tkey.getTSSPub().toSEC1(this.tKey.tssCurve, false), + // still need tssPubkey on the state? + // should compute from tkey as we support the account index + tssPubKey: this.tkey.getTSSPub(this.keyType, TSS_TAG_DEFAULT).toSEC1(tssCurve, false), signatures: result.signatures, userInfo: result.userInfo, }); @@ -1275,9 +1347,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when creating session."); } - const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey, { - accountIndex: this.state.accountIndex, - }); + const { tssShare } = await this.getTssShare(this.state.factorKey); if (!postBoxKey || !factorKey || !tssShare || !tssPubKey || !userInfo) { throw CoreKitError.userNotLoggedIn(); } @@ -1334,10 +1404,11 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { */ private async copyOrCreateShare(newFactorTSSIndex: number, newFactorPub: Point) { this.checkReady(); - if (!this.tKey.metadata.factorPubs || !Array.isArray(this.tKey.metadata.factorPubs[this.tKey.tssTag])) { + const tssData = this.getTssData(); + if (!tssData.factorPubs || !Array.isArray(tssData.factorPubs)) { throw CoreKitError.factorPubsMissing("'factorPubs' is missing in the metadata. Failed to copy factor public key."); } - if (!this.tKey.metadata.factorEncs || typeof this.tKey.metadata.factorEncs[this.tKey.tssTag] !== "object") { + if (!tssData.factorEncs || typeof tssData.factorEncs !== "object") { throw CoreKitError.factorEncsMissing("'factorEncs' is missing in the metadata. Failed to copy factor public key."); } if (!this.state.factorKey) { @@ -1346,7 +1417,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (VALID_SHARE_INDICES.indexOf(newFactorTSSIndex) === -1) { throw CoreKitError.newShareIndexInvalid(`Invalid share type provided (${newFactorTSSIndex}). Valid share types are ${VALID_SHARE_INDICES}.`); } - if (this.tKey.metadata.factorPubs[this.tKey.tssTag].length >= MAX_FACTORS) { + if (tssData.factorPubs.length >= MAX_FACTORS) { throw CoreKitError.maximumFactorsReached(`The maximum number of allowable factors (${MAX_FACTORS}) has been reached.`); } const authSignatures = await this.getSessionSignatures(); @@ -1357,6 +1428,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { newFactorPub, newTSSIndex: newFactorTSSIndex, refreshShares: this.state.tssShareIndex !== newFactorTSSIndex, // Refresh shares if we have a new factor key index. + tssTag: TSS_TAG_DEFAULT, }); } @@ -1410,7 +1482,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { additionalMetadata = {}; } - const { tssIndex } = await this.tKey.getTSSShare(factorKey); + const { tssIndex } = await this.getTssShare(factorKey); const factorPoint = getPubKeyPoint(factorKey, factorKeyCurve); const factorPub = factorPoint.toSEC1(factorKeyCurve, true).toString("hex"); @@ -1544,7 +1616,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (this._sigType === "ed25519" && this.state.accountIndex !== 0) { throw CoreKitError.default("Account index not supported for ed25519"); } - const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey); + const { tssShare } = await this.getTssShare(this.state.factorKey); const clientShareAdjusted = tssShare.mul(clientCoefficient).umod(ec.n); const clientShareAdjustedHex = ec.scalarToBuffer(clientShareAdjusted, Buffer).toString("hex"); diff --git a/tests/backwardCompatible.spec.ts b/tests/backwardCompatible.spec.ts index 5c244c6d..94c0249a 100644 --- a/tests/backwardCompatible.spec.ts +++ b/tests/backwardCompatible.spec.ts @@ -33,7 +33,7 @@ const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit) => { 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.getTssShare(new BN(factorkey.factorKey, "hex")); }; variable.forEach((testVariable) => { @@ -49,6 +49,7 @@ variable.forEach((testVariable) => { tssLib, storage: storageInstance, manualSync, + legacyFlag: true, }); const coreKitInstance = newCoreKitInstance(); @@ -69,6 +70,8 @@ variable.forEach((testVariable) => { idToken, }); + // console.log(coreKitInstance.tKey.metadata) + // console.log(coreKitInstance.state); // get key details await checkLogin(coreKitInstance); diff --git a/tests/bip340.spec.ts b/tests/bip340.spec.ts index 298d1009..39ec07d4 100644 --- a/tests/bip340.spec.ts +++ b/tests/bip340.spec.ts @@ -9,6 +9,7 @@ import { schnorr as bip340 } from '@noble/curves/secp256k1'; import { AsyncStorage, COREKIT_STATUS, MemoryStorage, WEB3AUTH_NETWORK, WEB3AUTH_NETWORK_TYPE, Web3AuthMPCCoreKit } from "../src"; import { bufferToElliptic, criticalResetAccount, mockLogin, mockLogin2 } from "./setup"; +import { getKeyCurve } from "@toruslabs/torus.js"; type TestVariable = { web3AuthNetwork: WEB3AUTH_NETWORK_TYPE; @@ -31,9 +32,7 @@ const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit, accountIndex = 0) 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"), { - accountIndex, - }); + await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex"), accountIndex ); }; const storageInstance = new MemoryStorage(); @@ -85,11 +84,10 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - checkPubKey = bufferToElliptic(coreKitInstance.getPubKey(), coreKitInstance.tKey.tssCurve); + const tssCurve = getKeyCurve(coreKitInstance.keyType) + checkPubKey = coreKitInstance.getPubKeyPoint().toEllipticPoint(tssCurve); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare } = await coreKitInstance.tKey.getTSSShare(new BN(factorkey.factorKey, "hex"), { - threshold: 0, - }); + const { tssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); checkTssShare = tssShare; if (manualSync) { @@ -125,9 +123,10 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - const newPubKey = bufferToElliptic(coreKitInstance.getPubKey(), coreKitInstance.tKey.tssCurve); + const tssCurve = getKeyCurve(coreKitInstance.keyType) + const newPubKey = coreKitInstance.getPubKeyPoint().toEllipticPoint(tssCurve); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare: newTssShare } = await coreKitInstance.tKey.getTSSShare(new BN(factorkey.factorKey, "hex")); + const { tssShare: newTssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); assert(checkPubKey.eq(newPubKey)); assert(checkTssShare.eq(newTssShare)); }); diff --git a/tests/ed25519.spec.ts b/tests/ed25519.spec.ts index 208beb5a..40efc6ad 100644 --- a/tests/ed25519.spec.ts +++ b/tests/ed25519.spec.ts @@ -8,6 +8,7 @@ import BN from "bn.js"; import { AsyncStorage, COREKIT_STATUS, ed25519, MemoryStorage, WEB3AUTH_NETWORK, WEB3AUTH_NETWORK_TYPE, Web3AuthMPCCoreKit } from "../src"; import { bufferToElliptic, criticalResetAccount, mockLogin, mockLogin2 } from "./setup"; +import { getKeyCurve } from "@toruslabs/torus.js"; type TestVariable = { web3AuthNetwork: WEB3AUTH_NETWORK_TYPE; @@ -30,9 +31,7 @@ const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit, accountIndex = 0) 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"), { - accountIndex, - }); + await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex") ,accountIndex); }; const storageInstance = new MemoryStorage(); @@ -48,6 +47,7 @@ variable.forEach((testVariable) => { tssLib, storage: storageInstance, manualSync, + legacyFlag: true, }); async function resetAccount() { @@ -84,11 +84,10 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - checkPubKey = bufferToElliptic(coreKitInstance.getPubKey(), coreKitInstance.tKey.tssCurve); + const tssCurve = getKeyCurve(coreKitInstance.keyType) + checkPubKey = bufferToElliptic(coreKitInstance.getPubKey(), tssCurve); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare } = await coreKitInstance.tKey.getTSSShare(new BN(factorkey.factorKey, "hex"), { - threshold: 0, - }); + const { tssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); checkTssShare = tssShare; if (manualSync) { @@ -124,9 +123,10 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - const newPubKey = bufferToElliptic(coreKitInstance.getPubKey(), coreKitInstance.tKey.tssCurve); + const tssCurve = getKeyCurve(coreKitInstance.keyType) + const newPubKey = bufferToElliptic(coreKitInstance.getPubKey(), tssCurve); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare: newTssShare } = await coreKitInstance.tKey.getTSSShare(new BN(factorkey.factorKey, "hex")); + const { tssShare: newTssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); assert(checkPubKey.eq(newPubKey)); assert(checkTssShare.eq(newTssShare)); }); diff --git a/tests/factors.spec.ts b/tests/factors.spec.ts index e3a75069..aada6af3 100644 --- a/tests/factors.spec.ts +++ b/tests/factors.spec.ts @@ -9,6 +9,7 @@ import BN from "bn.js"; import { COREKIT_STATUS, IAsyncStorage, IStorage, MemoryStorage, TssLibType, TssShareType, WEB3AUTH_NETWORK, Web3AuthMPCCoreKit } from "../src"; import { AsyncMemoryStorage, bufferToElliptic, criticalResetAccount, mockLogin } from "./setup"; +import { getKeyCurve } from "@toruslabs/torus.js"; type FactorTestVariable = { manualSync?: boolean; @@ -21,9 +22,9 @@ function getPubKeys(kit: Web3AuthMPCCoreKit, indices: number[]): EllipticPoint[] if (!kit.supportsAccountIndex) { indices = indices.filter((i) => i === 0); } + const tssCurve = getKeyCurve(kit.keyType) const pubKeys = indices.map((i) => { - kit.setTssWalletIndex(i); - return bufferToElliptic(kit.getPubKey()); + return kit.getPubKeyPoint( i).toEllipticPoint(tssCurve); }); return pubKeys; } diff --git a/tests/importRecovery.spec.ts b/tests/importRecovery.spec.ts index 8d3bbc8e..6964a4f9 100644 --- a/tests/importRecovery.spec.ts +++ b/tests/importRecovery.spec.ts @@ -6,6 +6,7 @@ import { tssLib as tssLibFROST } from "@toruslabs/tss-frost-lib"; import { AsyncStorage, MemoryStorage, TssLibType, TssShareType, WEB3AUTH_NETWORK } from "../src"; import { bufferToElliptic, criticalResetAccount, newCoreKitLogInInstance } from "./setup"; +import { getKeyCurve } from "@toruslabs/torus.js"; type ImportKeyTestVariable = { manualSync?: boolean; @@ -81,7 +82,7 @@ export const ImportTest = async (testVariable: ImportKeyTestVariable) => { const tssPubkey = bufferToElliptic(coreKitInstance3.getPubKey()); const exportedTssKey3 = await coreKitInstance3._UNSAFE_exportTssKey(); - const tssCurve = coreKitInstance3.tKey.tssCurve; + const tssCurve = getKeyCurve(coreKitInstance.keyType); const exportedPub = tssCurve.keyFromPrivate(exportedTssKey3).getPublic(); assert(tssPubkey.eq(exportedPub)); diff --git a/tests/login.spec.ts b/tests/login.spec.ts index 33a45ef3..fd0a4375 100644 --- a/tests/login.spec.ts +++ b/tests/login.spec.ts @@ -33,9 +33,7 @@ const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit, accountIndex = 0) 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"), { - accountIndex, - }); + await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex"), accountIndex ); }; const storageInstance = new MemoryStorage(); @@ -97,9 +95,7 @@ variable.forEach((testVariable) => { checkPubKey = bufferToElliptic(coreKitInstance.getPubKey()); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare } = await coreKitInstance.tKey.getTSSShare(new BN(factorkey.factorKey, "hex"), { - threshold: 0, - }); + const { tssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); checkTssShare = tssShare; if (manualSync) { @@ -137,7 +133,7 @@ variable.forEach((testVariable) => { await checkLogin(coreKitInstance); const newPubKey = bufferToElliptic(coreKitInstance.getPubKey()); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare: newTssShare } = await coreKitInstance.tKey.getTSSShare(new BN(factorkey.factorKey, "hex")); + const { tssShare: newTssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); assert(checkPubKey.eq(newPubKey)); assert(checkTssShare.eq(newTssShare)); }); diff --git a/tests/securityQuestion.spec.ts b/tests/securityQuestion.spec.ts index 3f1d788b..df74cc2c 100644 --- a/tests/securityQuestion.spec.ts +++ b/tests/securityQuestion.spec.ts @@ -63,7 +63,7 @@ export const TssSecurityQuestionsTest = async (newInstance: () => Promise securityQuestion.recoverFactor(instance, "wrong answer")); @@ -77,26 +77,26 @@ export const TssSecurityQuestionsTest = async (newInstance: () => Promise instance.tKey.getTSSShare(new BN(factor, "hex"))); + await assert.rejects(() => instance.getTssShare(new BN(factor, "hex"))); // recover factor // check wrong answer diff --git a/tests/sessionTime.spec.ts b/tests/sessionTime.spec.ts index f649fbdc..7175e4a4 100644 --- a/tests/sessionTime.spec.ts +++ b/tests/sessionTime.spec.ts @@ -75,6 +75,7 @@ variable.forEach(async (testVariable) => { manualSync, sessionTime, disableSessionManager, + legacyFlag: false, }); if (coreKitInstance.status === COREKIT_STATUS.INITIALIZED) await criticalResetAccount(coreKitInstance); } @@ -96,6 +97,7 @@ variable.forEach(async (testVariable) => { } }); + console.log(coreKitInstance.keyType) await coreKitInstance.loginWithJWT({ verifier: "torus-test-health", verifierId: parsedToken.email, diff --git a/tests/setup.ts b/tests/setup.ts index 8b6adc5f..7a66c35a 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -31,14 +31,10 @@ export const criticalResetAccount = async (coreKitInstance: Web3AuthMPCCoreKit): throw new Error("coreKitInstance is not set"); } - if (coreKitInstance.tKey.secp256k1Key) { - await coreKitInstance.tKey.CRITICAL_deleteTkey(); - } else { - await coreKitInstance.tKey.storageLayer.setMetadata({ - privKey: new BN(coreKitInstance.state.postBoxKey!, "hex"), - input: { message: "KEY_NOT_FOUND" }, - }); - } + await coreKitInstance.tKey.storageLayer.setMetadata({ + privKey: new BN(coreKitInstance.state.postBoxKey!, "hex"), + input: { message: "KEY_NOT_FOUND" }, + }); }; const privateKey = "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCD7oLrcKae+jVZPGx52Cb/lKhdKxpXjl9eGNa1MlY57A=="; From 9a25f60fe84abf38d7a3e30174a7192970ebf378 Mon Sep 17 00:00:00 2001 From: ieow Date: Mon, 10 Feb 2025 15:21:00 +0800 Subject: [PATCH 02/16] fix: add randomId verifier testcases --- package-lock.json | 130 ++---------------------------------------- package.json | 2 +- src/mpcCoreKit.ts | 6 +- tests/factors.spec.ts | 11 +++- 4 files changed, 19 insertions(+), 130 deletions(-) diff --git a/package-lock.json b/package-lock.json index 660ddb6e..933e5d5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "@toruslabs/metadata-helpers": "^6.0.0", "@toruslabs/openlogin-utils": "^8.2.1", "@toruslabs/session-manager": "^3.1.0", - "@toruslabs/torus.js": "15.2.0-alpha.0", + "@toruslabs/torus.js": "file:../torus.js/toruslabs-torus.js-15.1.1.tgz", "@toruslabs/tss-client": "^3.3.0-alpha.0", "@toruslabs/tss-frost-client": "^1.0.1-alpha.0", "@toruslabs/tss-frost-common": "^1.0.2-alpha.0", @@ -3804,30 +3804,6 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey/core/node_modules/@toruslabs/torus.js": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@toruslabs/torus.js/-/torus.js-15.1.1.tgz", - "integrity": "sha512-sLaXA1/R8KTTjU4t+teL3PPaJr2+j01QLYn5IY/t5uTD+1G2nzzfVWpkMDYrk9EfQYw0u4aKJ1lT7j9uKafMlg==", - "license": "MIT", - "dependencies": { - "@toruslabs/bs58": "^1.0.0", - "@toruslabs/constants": "^14.0.0", - "@toruslabs/eccrypto": "^5.0.4", - "@toruslabs/http-helpers": "^7.0.0", - "bn.js": "^5.2.1", - "elliptic": "^6.5.7", - "ethereum-cryptography": "^2.2.1", - "json-stable-stringify": "^1.1.1", - "loglevel": "^1.9.2" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, "node_modules/@tkey/service-provider-base": { "version": "15.2.1-alpha.0", "resolved": "https://registry.npmjs.org/@tkey/service-provider-base/-/service-provider-base-15.2.1-alpha.0.tgz", @@ -3867,30 +3843,6 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey/service-provider-torus/node_modules/@toruslabs/torus.js": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@toruslabs/torus.js/-/torus.js-15.1.1.tgz", - "integrity": "sha512-sLaXA1/R8KTTjU4t+teL3PPaJr2+j01QLYn5IY/t5uTD+1G2nzzfVWpkMDYrk9EfQYw0u4aKJ1lT7j9uKafMlg==", - "license": "MIT", - "dependencies": { - "@toruslabs/bs58": "^1.0.0", - "@toruslabs/constants": "^14.0.0", - "@toruslabs/eccrypto": "^5.0.4", - "@toruslabs/http-helpers": "^7.0.0", - "bn.js": "^5.2.1", - "elliptic": "^6.5.7", - "ethereum-cryptography": "^2.2.1", - "json-stable-stringify": "^1.1.1", - "loglevel": "^1.9.2" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, "node_modules/@tkey/share-serialization": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/@tkey/share-serialization/-/share-serialization-15.1.0.tgz", @@ -3930,30 +3882,6 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey/share-serialization/node_modules/@toruslabs/torus.js": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@toruslabs/torus.js/-/torus.js-15.1.1.tgz", - "integrity": "sha512-sLaXA1/R8KTTjU4t+teL3PPaJr2+j01QLYn5IY/t5uTD+1G2nzzfVWpkMDYrk9EfQYw0u4aKJ1lT7j9uKafMlg==", - "license": "MIT", - "dependencies": { - "@toruslabs/bs58": "^1.0.0", - "@toruslabs/constants": "^14.0.0", - "@toruslabs/eccrypto": "^5.0.4", - "@toruslabs/http-helpers": "^7.0.0", - "bn.js": "^5.2.1", - "elliptic": "^6.5.7", - "ethereum-cryptography": "^2.2.1", - "json-stable-stringify": "^1.1.1", - "loglevel": "^1.9.2" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, "node_modules/@tkey/storage-layer-torus": { "version": "15.2.1-alpha.0", "resolved": "file:../tkey/packages/storage-layer-torus/tkey-storage-layer-torus-15.2.1-alpha.0.tgz", @@ -3978,7 +3906,7 @@ "node_modules/@tkey/tss": { "version": "15.2.1-alpha.0", "resolved": "file:../tkey/packages/tss/tkey-tss-15.2.1-alpha.0.tgz", - "integrity": "sha512-KncB4Ws/+Sj0dy/3fh+0dv299E9i7Rrkf4VeYeeV0D5ErlqCze8SWXoX9eQXdUgdF0ryxUHNLckjg6ljCcmXMg==", + "integrity": "sha512-qc+aZ3PnAkbUZlcbKAcFJ5rVmnqZuJnFhCp/y031BOJWmCH+Lw4wwlSAqrzH9Z9NEi+D7QnOS8r2eay4dTd56g==", "license": "ISC", "dependencies": { "@tkey/common-types": "^15.2.1-alpha.0", @@ -3994,30 +3922,6 @@ "ethereum-cryptography": "^2.1.3" } }, - "node_modules/@tkey/tss/node_modules/@toruslabs/torus.js": { - "version": "15.1.1", - "resolved": "file:../torus.js/toruslabs-torus.js-15.1.1.tgz", - "integrity": "sha512-kkLuZ9vpmWZTklva+RQFKozDMCR2ydhR5WBn9bbgJBZqVP75FSzLZL0LQYrFqBPMgKgV22uOQ8quXW6T+Kko/g==", - "license": "MIT", - "dependencies": { - "@toruslabs/bs58": "^1.0.0", - "@toruslabs/constants": "^14.0.0", - "@toruslabs/eccrypto": "^5.0.4", - "@toruslabs/http-helpers": "^7.0.0", - "bn.js": "^5.2.1", - "elliptic": "^6.5.7", - "ethereum-cryptography": "^2.2.1", - "json-stable-stringify": "^1.1.1", - "loglevel": "^1.9.2" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -4118,30 +4022,6 @@ } } }, - "node_modules/@toruslabs/customauth/node_modules/@toruslabs/torus.js": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@toruslabs/torus.js/-/torus.js-15.1.1.tgz", - "integrity": "sha512-sLaXA1/R8KTTjU4t+teL3PPaJr2+j01QLYn5IY/t5uTD+1G2nzzfVWpkMDYrk9EfQYw0u4aKJ1lT7j9uKafMlg==", - "license": "MIT", - "dependencies": { - "@toruslabs/bs58": "^1.0.0", - "@toruslabs/constants": "^14.0.0", - "@toruslabs/eccrypto": "^5.0.4", - "@toruslabs/http-helpers": "^7.0.0", - "bn.js": "^5.2.1", - "elliptic": "^6.5.7", - "ethereum-cryptography": "^2.2.1", - "json-stable-stringify": "^1.1.1", - "loglevel": "^1.9.2" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, "node_modules/@toruslabs/eccrypto": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@toruslabs/eccrypto/-/eccrypto-5.0.4.tgz", @@ -4701,9 +4581,9 @@ } }, "node_modules/@toruslabs/torus.js": { - "version": "15.2.0-alpha.0", - "resolved": "https://registry.npmjs.org/@toruslabs/torus.js/-/torus.js-15.2.0-alpha.0.tgz", - "integrity": "sha512-W0HXmffYTbA9pFC3gdj6ON+FsmzJlSksT6hW5mDkRLZp1qSprYppjHnnnelq5n46yOs+290En8LP5s/U5viluw==", + "version": "15.1.1", + "resolved": "file:../torus.js/toruslabs-torus.js-15.1.1.tgz", + "integrity": "sha512-kkLuZ9vpmWZTklva+RQFKozDMCR2ydhR5WBn9bbgJBZqVP75FSzLZL0LQYrFqBPMgKgV22uOQ8quXW6T+Kko/g==", "license": "MIT", "dependencies": { "@toruslabs/bs58": "^1.0.0", diff --git a/package.json b/package.json index b150dc06..76b760ba 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "@toruslabs/metadata-helpers": "^6.0.0", "@toruslabs/openlogin-utils": "^8.2.1", "@toruslabs/session-manager": "^3.1.0", - "@toruslabs/torus.js": "15.2.0-alpha.0", + "@toruslabs/torus.js": "file:../torus.js/toruslabs-torus.js-15.1.1.tgz", "@toruslabs/tss-client": "^3.3.0-alpha.0", "@toruslabs/tss-frost-client": "^1.0.1-alpha.0", "@toruslabs/tss-frost-common": "^1.0.2-alpha.0", diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index dddf41f3..1e19003a 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -828,8 +828,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { // Suppress client logs if logging is disabled. client.log = (msg: string) => { if (!this.enableLogging) return; - // eslint-disable-next-line no-console - console.log(msg); + log.debug(msg); }; const serverCoeffs: Record = {}; @@ -1193,9 +1192,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { // if both keyType library is avaiable, initialize secp256k1 first as secp256k1 is initialize offline + const importTssBuf = importTssKey ? Buffer.from(importTssKey, "hex") : undefined; // check if key is in the tsslib and keytype exists await this.tKey.initializeTss({ - importKey: importTssKey ? Buffer.from(importTssKey, "hex") : undefined, + importKey: importTssBuf, factorPub, deviceTSSShare, deviceTSSIndex, diff --git a/tests/factors.spec.ts b/tests/factors.spec.ts index aada6af3..2397a8ed 100644 --- a/tests/factors.spec.ts +++ b/tests/factors.spec.ts @@ -8,14 +8,17 @@ import { tssLib as tssLibFROST } from "@toruslabs/tss-frost-lib"; import BN from "bn.js"; import { COREKIT_STATUS, IAsyncStorage, IStorage, MemoryStorage, TssLibType, TssShareType, WEB3AUTH_NETWORK, Web3AuthMPCCoreKit } from "../src"; -import { AsyncMemoryStorage, bufferToElliptic, criticalResetAccount, mockLogin } from "./setup"; +import { AsyncMemoryStorage, criticalResetAccount, mockLogin } from "./setup"; import { getKeyCurve } from "@toruslabs/torus.js"; +import { randomId } from "@toruslabs/customauth"; +import log from "loglevel"; type FactorTestVariable = { manualSync?: boolean; storage?: IAsyncStorage | IStorage; email: string; tssLib?: TssLibType; + resetAccount? : false }; function getPubKeys(kit: Web3AuthMPCCoreKit, indices: number[]): EllipticPoint[] { @@ -53,7 +56,12 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = }; async function beforeTest() { + if (testVariable.resetAccount === false) { + log.debug("skipping reset account"); + return ; + } const resetInstance = await newInstance(); + await criticalResetAccount(resetInstance); await resetInstance.logout(); } @@ -182,6 +190,7 @@ const variable: FactorTestVariable[] = [ { manualSync: false, storage: new AsyncMemoryStorage(), email: "testmail1015" }, { manualSync: true, storage: new MemoryStorage(), email: "testmail1012ed25519", tssLib: tssLibFROST }, + { manualSync: true, storage: new MemoryStorage(), email: randomId() , tssLib: tssLibFROST , resetAccount: false}, ]; variable.forEach(async (testVariable) => { From b80ad8aff110321b98bdfae09af8d2619aa03c43 Mon Sep 17 00:00:00 2001 From: ieow Date: Tue, 11 Feb 2025 19:48:28 +0800 Subject: [PATCH 03/16] fix: enable multicurve fix tests add multicurve tests --- src/interfaces.ts | 12 +- src/mpcCoreKit.ts | 197 +++++++++++++++++++++---------- tests/backwardCompatible.spec.ts | 2 +- tests/bip340.spec.ts | 2 +- tests/ed25519.spec.ts | 2 +- tests/factors.spec.ts | 3 +- tests/gating.spec.ts | 2 +- tests/login.spec.ts | 4 +- tests/multiCurveTest.ts | 129 ++++++++++++++++++++ tests/securityQuestion.spec.ts | 2 +- tests/sessionTime.spec.ts | 2 +- tests/setup.ts | 14 ++- 12 files changed, 292 insertions(+), 79 deletions(-) create mode 100644 tests/multiCurveTest.ts diff --git a/src/interfaces.ts b/src/interfaces.ts index 3b19cb64..a3aee429 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -95,7 +95,9 @@ export type OAuthLoginParams = (SubVerifierDetailsParams | AggregateVerifierLogi /** * Key to import key into Tss during first time login. */ - importTssKey?: string; + importTssKey?: { + [K in KeyType]: string; + }; /** * For new users, use SFA key if user was registered with SFA before. @@ -161,7 +163,9 @@ export interface JWTLoginParams { /** * Key to import key into Tss during first time login. */ - importTssKey?: string; + importTssKey?: { + [K in KeyType]?: string; + }; /** * For new users, use SFA key if user was registered with SFA before. @@ -201,7 +205,7 @@ export interface Web3AuthOptions { /** * The threshold signing library to use. */ - tssLib: TssLibType; + tssLibs: TssLibType[]; /** * @defaultValue `false` @@ -354,7 +358,7 @@ export interface IMPCContext { updateState: (newState: Partial) => void; getUserInfo: () => UserInfo; setupTkey: (params?: { - providedImportKey?: string; + providedImportKey?: { [key in KeyType]?: string }; sfaLoginResponse?: TorusKey | TorusLoginResponse | TorusAggregateLoginResponse; userInfo?: UserInfo; importingSFAKey?: boolean; diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 1e19003a..7be699b7 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -3,7 +3,7 @@ import { CoreError } from "@tkey/core"; import { ShareSerializationModule } from "@tkey/share-serialization"; import { TorusStorageLayer } from "@tkey/storage-layer-torus"; import { factorKeyCurve, getPubKeyPoint, lagrangeInterpolation, TKeyTSS, TSS_TAG_DEFAULT, TSSTorusServiceProvider } from "@tkey/tss"; -import { SIGNER_MAP } from "@toruslabs/constants"; +import { SIG_TYPE, SIGNER_MAP, WEB3AUTH_SIG_TYPE } from "@toruslabs/constants"; import { AGGREGATE_VERIFIER, TORUS_METHOD, TorusAggregateLoginResponse, TorusLoginResponse, UX_MODE } from "@toruslabs/customauth"; import type { UX_MODE_TYPE } from "@toruslabs/customauth/dist/types/utils/enums"; import { Ed25519Curve, Secp256k1Curve } from "@toruslabs/elliptic-wrapper"; @@ -12,7 +12,7 @@ import { keccak256 } from "@toruslabs/metadata-helpers"; import { SessionManager } from "@toruslabs/session-manager"; import { getKeyCurve, Torus as TorusUtils, TorusKey } from "@toruslabs/torus.js"; import { Client, getDKLSCoeff, setupSockets } from "@toruslabs/tss-client"; -import type { WasmLib as DKLSWasmLib } from "@toruslabs/tss-dkls-lib"; +import { type WasmLib as DKLSWasmLib } from "@toruslabs/tss-dkls-lib"; import { sign as signFrost } from "@toruslabs/tss-frost-client"; import type { WasmLib as FrostWasmLibEd25519 } from "@toruslabs/tss-frost-lib"; import type { WasmLib as FrostWasmLibBip340 } from "@toruslabs/tss-frost-lib-bip340"; @@ -98,9 +98,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { private ready = false; - private _tssLib: TssLibType; + private _tssLibs: TssLibType[]; - private wasmLib: DKLSWasmLib | FrostWasmLibEd25519 | FrostWasmLibBip340; + private wasmLib: { + [SIG_TYPE.ECDSA_SECP256K1]?: DKLSWasmLib; + [SIG_TYPE.ED25519]?: FrostWasmLibEd25519; + [SIG_TYPE.BIP340]?: FrostWasmLibBip340; + } = {}; private _keyType: KeyType; @@ -110,14 +114,28 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { private sessionSigGenerator: ISessionSigGenerator; + private supportedCurveKeyTypes: Set = new Set(); + + private supportedSigTypes: Set = new Set(); + constructor(options: Web3AuthOptions) { if (!options.web3AuthClientId) { throw CoreKitError.clientIdInvalid(); } - this._tssLib = options.tssLib; - this._keyType = options.tssLib.keyType as KeyType; - this._sigType = options.tssLib.sigType as SigType; + options.tssLibs.forEach((tssLibItem) => { + this.supportedCurveKeyTypes.add(tssLibItem.keyType as KeyType); + this.supportedSigTypes.add(tssLibItem.sigType as SigType); + }); + this._keyType = options.tssLibs[0].keyType as KeyType; + this._sigType = options.tssLibs[0].sigType as SigType; + this._tssLibs = options.tssLibs; + + if (!options.legacyFlag) { + options.legacyFlag = false; + } else if (this.supportedCurveKeyTypes.size > 1) { + throw CoreKitError.invalidConfig("Legacy flag is not supported for multiple curves"); + } const isNodejsOrRN = this.isNodejsOrRN(options.uxMode); @@ -136,7 +154,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!options.disableHashedFactorKey) options.disableHashedFactorKey = false; if (!options.hashedFactorNonce) options.hashedFactorNonce = options.web3AuthClientId; if (options.disableSessionManager === undefined) options.disableSessionManager = false; - if (!options.legacyFlag) options.legacyFlag = false; this.sessionSigGenerator = new DefaultSessionSigGeneratorPlugin(this); this.options = options as Web3AuthOptionsWithDefaults; @@ -225,9 +242,16 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { public setTkeyType(tkeyType: KeyType) { // check tkeyType is supported by tssLib + if (!this.supportedCurveKeyTypes.has(tkeyType)) throw CoreError.default("KeyType not supported, please provide valid tssLib"); this._keyType = tkeyType; } + public setSigType(sigType: WEB3AUTH_SIG_TYPE) { + // check tkeyType is supported by tssLib + if (!this.supportedSigTypes.has(sigType)) throw CoreError.default("SigType not supported, please provide valid tssLib"); + this._sigType = sigType; + } + public getTssShare(factorkey: BN, accountIndex?: number) { return this.tkey.getTSSShare(factorkey, { tssTag: TSS_TAG_DEFAULT, @@ -236,8 +260,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { }); } - public getTssData(args: { skipThrow: boolean } = { skipThrow: false }) { - const result = this.tkey.metadata.getTssData(this.keyType, TSS_TAG_DEFAULT); + public getTssData(args: { skipThrow: boolean; keyType?: KeyType } = { skipThrow: false }) { + const result = this.tkey.metadata.getTssData(args.keyType ?? this.keyType, TSS_TAG_DEFAULT); if (!result && !args.skipThrow) { throw CoreKitError.noMetadataFound(); } @@ -411,7 +435,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } const existingSFAKey = loginResponse.finalKeyData.privKey.padStart(64, "0"); await this.setupTkey({ - providedImportKey: existingSFAKey, + providedImportKey: { secp256k1: existingSFAKey }, sfaLoginResponse: loginResponse, userInfo, importingSFAKey: true, @@ -448,7 +472,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { this.torusSp.verifierName = verifier; this.torusSp.verifierId = verifierId; - if (registerExistingSFAKey && importTssKey) { + if (registerExistingSFAKey && importTssKey && (importTssKey.secp256k1 || this.options.legacyFlag)) { throw CoreKitError.invalidConfig("Cannot import TSS key and register SFA key at the same time."); } @@ -483,7 +507,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } const existingSFAKey = loginResponse.finalKeyData.privKey.padStart(64, "0"); await this.setupTkey({ - providedImportKey: existingSFAKey, + providedImportKey: { [this._keyType]: existingSFAKey }, importingSFAKey: true, sfaLoginResponse: loginResponse, userInfo: { ...parseToken(idToken), verifier, verifierId }, @@ -555,6 +579,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { public async inputFactorKey(factorKey: BN): Promise { this.checkReady(); + + if (this.options.legacyFlag) { + // Check for existing curve in tssData for legacy mode + const tssData = this.getTssData({ skipThrow: true }); + if (!tssData) throw CoreKitError.default("Legacy mode only support single curve, please congfiure with correct keyType"); + } + try { // input tkey device share when required share > 0 ( or not reconstructed ) // assumption tkey shares will not changed @@ -758,7 +789,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { signatures: string[]; }> { const { sessionSignatures } = params || {}; - this.wasmLib = await this.loadTssWasm(); + + await this.loadTssWasm(SIG_TYPE.ECDSA_SECP256K1); + const dklsWasm = this.wasmLib[SIG_TYPE.ECDSA_SECP256K1]; + // PreSetup const { tssShareIndex } = this.state; const tssPubKey = this.getPubKeyPoint(); @@ -813,17 +847,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { // Client lib expects pub key in XY-format, base64-encoded. const tssPubKeyBase64 = Buffer.from(tssPubKey.toSEC1(secp256k1).subarray(1)).toString("base64"); - const client = new Client( - currentSession, - clientIndex, - partyIndexes, - endpoints, - sockets, - share, - tssPubKeyBase64, - true, - this.wasmLib as DKLSWasmLib - ); + const client = new Client(currentSession, clientIndex, partyIndexes, endpoints, sockets, share, tssPubKeyBase64, true, dklsWasm); // Suppress client logs if logging is disabled. client.log = (msg: string) => { @@ -856,7 +880,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { keyTweak?: BN; } ): Promise { - this.wasmLib = await this.loadTssWasm(); + // this.wasmLib = await this.loadTssWasm(); if (this._sigType === "ecdsa-secp256k1") { if (opts?.keyTweak) { throw CoreKitError.default("key tweaking not supported for ecdsa-secp256k1"); @@ -1072,7 +1096,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } public async setupTkey(params?: { - providedImportKey?: string; + providedImportKey?: { [k in KeyType]?: string }; sfaLoginResponse?: TorusKey | TorusLoginResponse | TorusAggregateLoginResponse; userInfo?: UserInfo; importingSFAKey?: boolean; @@ -1102,15 +1126,15 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } const existingUser = await this.isMetadataPresent(this.state.postBoxKey); - let importKey = providedImportKey; + const importKey = providedImportKey ?? {}; if (!existingUser) { if (!importKey && this.useClientGeneratedTSSKey) { if (this.keyType === KeyType.ed25519) { const k = generateEd25519Seed(); - importKey = k.toString("hex"); + importKey.ed25519 = k.toString("hex"); } else if (this.keyType === KeyType.secp256k1) { const k = secp256k1.genKeyPair().getPrivate(); - importKey = scalarBNToBufferSEC1(k).toString("hex"); + importKey.secp256k1 = scalarBNToBufferSEC1(k).toString("hex"); } else { throw CoreKitError.default(`Unsupported key type and sig type combination: ${this.keyType}, ${this._sigType}`); } @@ -1120,7 +1144,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } await this.handleNewUser(importKey, importingSFAKey); } else { - if (importKey) { + if (importKey && Object.keys(importKey).length > 0) { throw CoreKitError.tssKeyImportNotAllowed(); } await this.handleExistingUser(); @@ -1171,7 +1195,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } // mutation function - private async handleNewUser(importTssKey?: string, isSfaKey?: boolean) { + private async handleNewUser(importTssKey?: { [k in KeyType]?: string }, isSfaKey?: boolean) { await this.atomicSync(async () => { // Generate or use hash factor and initialize tkey with it. let factorKey: BN; @@ -1190,33 +1214,37 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const deviceTSSShare = ec.genKeyPair().getPrivate(); await this.tKey.initialize(); - // if both keyType library is avaiable, initialize secp256k1 first as secp256k1 is initialize offline + // only consider 2 types of curve, will change the logic in the future if there are more key types curves - const importTssBuf = importTssKey ? Buffer.from(importTssKey, "hex") : undefined; - // check if key is in the tsslib and keytype exists - await this.tKey.initializeTss({ - importKey: importTssBuf, - factorPub, - deviceTSSShare, - deviceTSSIndex, - tssKeyType: this._keyType, - serverOpts: { - // selectedServers: [], - authSignatures: this.state.signatures, - }, - }); + // if both keyType library is avaiable, initialize secp256k1 first as secp256k1 is initialize offline - //TODO resolve this - // if both key type available - // if () { - // await this.tKey.initializeTss({ - // importKey: importTssKey? Buffer.from(importTssKey) : undefined, tssKeyType: this._keyType, - // serverOpts: { - // // selectedServers: [], - // authSignatures: this.state.signatures - // } - // }); - // } + if (this.supportedCurveKeyTypes.has(KeyType.secp256k1)) { + const importTssBuf = importTssKey.secp256k1 ? Buffer.from(importTssKey.secp256k1, "hex") : undefined; + // check if key is in the tsslib and keytype exists + await this.tKey.initializeTss({ + importKey: importTssBuf, + factorPub, + deviceTSSShare, + deviceTSSIndex, + tssKeyType: KeyType.secp256k1, + serverOpts: { + // selectedServers: [], + authSignatures: this.state.signatures, + }, + }); + } + if (this.supportedCurveKeyTypes.has(KeyType.ed25519)) { + const importTssBuf = importTssKey.ed25519 ? Buffer.from(importTssKey.ed25519, "hex") : undefined; + // check if key is in the tsslib and keytype exists + await this.tKey.initializeTss({ + importKey: importTssBuf, + tssKeyType: KeyType.ed25519, + serverOpts: { + // selectedServers: [], + authSignatures: this.state.signatures, + }, + }); + } // Finalize initialization. await this.tKey.reconstructKey(); @@ -1248,6 +1276,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { private async handleExistingUser() { await this.tKey.initialize({ neverInitializeNewKey: true }); + + if (this.options.legacyFlag) { + // Check for existing curve in tssData for legacy mode + const tssData = this.getTssData({ skipThrow: true }); + if (!tssData) throw CoreKitError.default("Legacy mode only support single curve, please congfiure with correct keyType"); + } + if (this.options.disableHashedFactorKey) { return; } @@ -1278,6 +1313,32 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { log.warn("AccountIndex should be 0"); this.state.accountIndex = 0; } + + let newCurveKeyType = false; + for (const keyType of this.supportedCurveKeyTypes) { + const tssData = this.getTssData({ skipThrow: true, keyType }); + if (!tssData) { + newCurveKeyType = true; + } + } + + if (newCurveKeyType) { + this.atomicSync(async () => { + // check for missing curve and initialize it + for (const keyType of this.supportedCurveKeyTypes) { + const tssData = this.getTssData({ skipThrow: true, keyType }); + if (!tssData) { + await this.tKey.initializeTss({ + tssKeyType: keyType, + serverOpts: { + authSignatures: this.state.signatures, + }, + }); + } + } + }); + } + // Read tss meta data. const { tssIndex: tssShareIndex } = await this.getTssShare(factorKey); const tssCurve = getKeyCurve(this._keyType); @@ -1630,8 +1691,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const pubKeyHex = ec.pointToBuffer(tssPubKeyPoint, Buffer).toString("hex"); const serverCoefficientsHex = serverCoefficients.map((c) => ec.scalarToBuffer(c, Buffer).toString("hex")); const authSignatures = await this.getSessionSignatures(); + + await this.loadTssWasm(this._sigType); + + const frostlib = this.sigType === SIG_TYPE.BIP340 ? this.wasmLib[SIG_TYPE.BIP340] : this.wasmLib[SIG_TYPE.ED25519]; const signature = await signFrost( - this.wasmLib as FrostWasmLibEd25519 | FrostWasmLibBip340, + frostlib, session, authSignatures, serverXCoords, @@ -1648,8 +1713,18 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return Buffer.from(signature, "hex"); } - private async loadTssWasm() { - if (this.wasmLib) return this.wasmLib; - return this._tssLib.load(); + private async loadTssWasm(sigType: WEB3AUTH_SIG_TYPE) { + if (this.wasmLib[sigType]) { + return this.wasmLib[sigType]; + } + + if (this.supportedSigTypes.has(sigType)) { + const matchLibs = this._tssLibs.find((x) => x.sigType === sigType); + if (sigType === SIG_TYPE.ECDSA_SECP256K1) { + this.wasmLib[sigType] = (await matchLibs?.load()) as DKLSWasmLib; + } + if (sigType === SIG_TYPE.ED25519 || sigType === SIG_TYPE.BIP340) this.wasmLib[sigType] = (await matchLibs?.load()) as FrostWasmLibEd25519; + } + return this.wasmLib; } } diff --git a/tests/backwardCompatible.spec.ts b/tests/backwardCompatible.spec.ts index 94c0249a..65084bcf 100644 --- a/tests/backwardCompatible.spec.ts +++ b/tests/backwardCompatible.spec.ts @@ -46,7 +46,7 @@ variable.forEach((testVariable) => { web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLib, + tssLibs: [tssLib], storage: storageInstance, manualSync, legacyFlag: true, diff --git a/tests/bip340.spec.ts b/tests/bip340.spec.ts index 39ec07d4..db8bb961 100644 --- a/tests/bip340.spec.ts +++ b/tests/bip340.spec.ts @@ -45,7 +45,7 @@ variable.forEach((testVariable) => { web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLib, + tssLibs : [tssLib], storage: storageInstance, manualSync, }); diff --git a/tests/ed25519.spec.ts b/tests/ed25519.spec.ts index 40efc6ad..11e9fbfc 100644 --- a/tests/ed25519.spec.ts +++ b/tests/ed25519.spec.ts @@ -44,7 +44,7 @@ variable.forEach((testVariable) => { web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLib, + tssLibs: [tssLib], storage: storageInstance, manualSync, legacyFlag: true, diff --git a/tests/factors.spec.ts b/tests/factors.spec.ts index 2397a8ed..6973fa4b 100644 --- a/tests/factors.spec.ts +++ b/tests/factors.spec.ts @@ -34,13 +34,14 @@ function getPubKeys(kit: Web3AuthMPCCoreKit, indices: number[]): EllipticPoint[] export const FactorManipulationTest = async (testVariable: FactorTestVariable) => { const { email, tssLib } = testVariable; + const tsslibs = tssLib ? [tssLib] : [tssLibDKLS]; const newInstance = async () => { const instance = new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, baseUrl: "http://localhost:3000", uxMode: "nodejs", - tssLib: tssLib || tssLibDKLS, + tssLibs: tsslibs, storage: testVariable.storage, manualSync: testVariable.manualSync, }); diff --git a/tests/gating.spec.ts b/tests/gating.spec.ts index 1cb68682..4b786eca 100644 --- a/tests/gating.spec.ts +++ b/tests/gating.spec.ts @@ -52,7 +52,7 @@ variable.forEach((testVariable) => { web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLib, + tssLibs: [tssLib], storage: new MemoryStorage(), manualSync, }); diff --git a/tests/login.spec.ts b/tests/login.spec.ts index fd0a4375..57a311d8 100644 --- a/tests/login.spec.ts +++ b/tests/login.spec.ts @@ -46,7 +46,7 @@ variable.forEach((testVariable) => { web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLib, + tssLibs: [tssLib], storage: storageInstance, manualSync, }); @@ -63,7 +63,7 @@ variable.forEach((testVariable) => { web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLib, + tssLibs: [tssLib], storage: storageInstance, manualSync, }); diff --git a/tests/multiCurveTest.ts b/tests/multiCurveTest.ts new file mode 100644 index 00000000..e4433bcb --- /dev/null +++ b/tests/multiCurveTest.ts @@ -0,0 +1,129 @@ +import { COREKIT_STATUS } from './../src/interfaces'; +import dklslib from "@toruslabs/tss-dkls-lib"; +import frostLib from "@toruslabs/tss-frost-lib"; +import frostBip340lib from "@toruslabs/tss-frost-lib-bip340"; + +import { expect } from "chai"; +import { describe, it } from "node:test"; +import { MemoryStorage, sigToRSV, WEB3AUTH_NETWORK, Web3AuthMPCCoreKit } from "src"; +import { mockLogin2 } from "./setup"; +import { KeyType } from '@tkey/common-types'; +import { BN } from 'bn.js'; +import { MockStorageLayer } from '@tkey/storage-layer-torus'; +import { secp256k1 } from '@noble/curves/secp256k1'; +import { ed25519 } from '@noble/curves/ed25519'; +import { bytesToHex, utf8ToBytes, bytesToNumberBE } from '@noble/curves/abstract/utils'; +import { keccak_256 } from '@noble/hashes/sha3'; + +import { schnorr as bip340 } from '@noble/curves/secp256k1'; + + +const web3AuthNetwork = WEB3AUTH_NETWORK.DEVNET; +const manualSync = false; +const storageInstance = new MemoryStorage(); +const verifierId = "multicurvetest" + +const mockSL = new MockStorageLayer({ + dataMap: {}, + lockMap: {}, +}); + +describe("multiCurveTest", () => { + // + const newCoreKitInstance = () => + new Web3AuthMPCCoreKit({ + web3AuthClientId: "torus-key-test", + web3AuthNetwork, + baseUrl: "http://localhost:3000", + uxMode: "nodejs", + tssLibs : [dklslib, frostLib, frostBip340lib], + storage: storageInstance, + manualSync, + }); + + + const testAllSigning = async (instance: Web3AuthMPCCoreKit) => { + const message = "message to sign"; + + + instance.setTkeyType(KeyType.secp256k1) + instance.setSigType("ecdsa-secp256k1") + + const hash = keccak_256(message); + const result = await instance.sign(Buffer.from(hash), {hashed: true}) + + const {r, s } = sigToRSV(result); + + // new secp256k1.Signature() + const validsecp256k1 = secp256k1.verify({ + r: bytesToNumberBE(r), + s: bytesToNumberBE(s), + }, bytesToHex(hash), bytesToHex(instance.getPubKey(false))) + expect(validsecp256k1).eq(true); + + instance.setSigType("bip340"); + const result2 = await instance.sign( Buffer.from(utf8ToBytes(message)), {hashed: false}) + + const validb340 = bip340.verify(bytesToHex(result2), bytesToHex(utf8ToBytes(message)), bytesToHex(instance.getPubKeyBip340())); + expect(validb340).eq(true); + + + instance.setSigType("ed25519") + instance.setTkeyType(KeyType.ed25519) + const result3 = await instance.sign(Buffer.from(message), { hashed: false }) + const valided25519 = ed25519.verify(bytesToHex(result3), bytesToHex(Buffer.from(message)), bytesToHex( new Uint8Array(instance.getPubKeyEd25519()) ) ) + expect(valided25519).eq(true); + + } + + it("should able to initialize with multiple curve/ tsslib", async () => { + const instance = newCoreKitInstance(); + await instance.init({ handleRedirectResult: false, rehydrate: false }); + + // mock storage layer + instance.tKey.storageLayer = mockSL; + + + const { idToken, parsedToken } = await mockLogin2(verifierId); + + await instance.loginWithJWT({ + verifier: "torus-test-health", + verifierId: parsedToken.email, + idToken, + }); + + expect(instance.status).eq("LOGGED_IN"); + + + await testAllSigning(instance); + + + const recoverFactor = await instance.enableMFA({}) + console.log(recoverFactor); + + await testAllSigning(instance); + + + const instance2 = newCoreKitInstance(); + await instance2.init({ handleRedirectResult: false, rehydrate: false }); + + // mock storage layer + instance2.tKey.storageLayer = mockSL; + + const { idToken: idToken2, parsedToken: parsedToken2 } = await mockLogin2(verifierId); + await instance2.loginWithJWT({ + verifier: "torus-test-health", + verifierId: parsedToken2.email, + idToken: idToken2, + }); + + expect(instance2.status).eq(COREKIT_STATUS.REQUIRED_SHARE); + + await instance2.inputFactorKey(new BN(recoverFactor, "hex")); + expect(instance2.status).eq(COREKIT_STATUS.LOGGED_IN); + + await testAllSigning(instance2); + + }) + +}); \ No newline at end of file diff --git a/tests/securityQuestion.spec.ts b/tests/securityQuestion.spec.ts index df74cc2c..ae24366a 100644 --- a/tests/securityQuestion.spec.ts +++ b/tests/securityQuestion.spec.ts @@ -132,7 +132,7 @@ variable.forEach(async (testVariable) => { web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, baseUrl: "http://localhost:3000", uxMode: "nodejs", - tssLib, + tssLibs: [tssLib], storage: storageInstance, manualSync: testVariable.manualSync, }); diff --git a/tests/sessionTime.spec.ts b/tests/sessionTime.spec.ts index 7175e4a4..0fae1a58 100644 --- a/tests/sessionTime.spec.ts +++ b/tests/sessionTime.spec.ts @@ -70,7 +70,7 @@ variable.forEach(async (testVariable) => { web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLib, + tssLibs : [tssLib], storage: new MemoryStorage(), manualSync, sessionTime, diff --git a/tests/setup.ts b/tests/setup.ts index 7a66c35a..9a05553c 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -99,13 +99,14 @@ export const newCoreKitLogInInstance = async ({ importTssKey?: string; registerExistingSFAKey?: boolean; login?: LoginFunc; -}) => { + }) => { + const tssLibs = [tssLib || tssLibDKLS]; const instance = new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", web3AuthNetwork: network, baseUrl: "http://localhost:3000", uxMode: "nodejs", - tssLib: tssLib || tssLibDKLS, + tssLibs: tssLibs, storage: storageInstance, manualSync, }); @@ -116,7 +117,7 @@ export const newCoreKitLogInInstance = async ({ verifier: "torus-test-health", verifierId: parsedToken.email, idToken, - importTssKey, + importTssKey: importTssKey ? { [tssLibs[0].keyType] : importTssKey} : undefined, registerExistingSFAKey }); @@ -136,13 +137,16 @@ export const loginWithSFA = async ({ storageInstance: IStorage | IAsyncStorage; tssLib?: TssLibType; login?: LoginFunc; -}): Promise => { + }): Promise => { + + const tssLibs = [tssLib || tssLibDKLS] + const instance = new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", web3AuthNetwork: network, baseUrl: "http://localhost:3000", uxMode: "nodejs", - tssLib: tssLib || tssLibDKLS, + tssLibs: tssLibs, storage: storageInstance, manualSync, }); From 88bbf5d70f758c49d7a7f24ffb98b28c0c8f2e2c Mon Sep 17 00:00:00 2001 From: ieow Date: Wed, 12 Feb 2025 14:48:08 +0800 Subject: [PATCH 04/16] feat: refactor multicurve --- src/interfaces.ts | 23 ++- src/mpcCoreKit.ts | 317 +++++++++++++++++++++------------------- tests/multiCurveTest.ts | 17 +-- 3 files changed, 177 insertions(+), 180 deletions(-) diff --git a/src/interfaces.ts b/src/interfaces.ts index a3aee429..74c682d4 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -87,8 +87,7 @@ export type MPCKeyDetails = { requiredFactors: number; totalFactors: number; shareDescriptions: ShareDescriptionMap; - keyType: KeyType; - tssPubKey?: TkeyPoint; + supportedKeyType: KeyType[]; }; export type OAuthLoginParams = (SubVerifierDetailsParams | AggregateVerifierLoginParams) & { @@ -187,7 +186,6 @@ export interface Web3AuthState { postboxKeyNodeIndexes?: number[]; userInfo?: UserInfo; tssShareIndex?: number; - tssPubKey?: Buffer; accountIndex: number; factorKey?: BN; } @@ -487,14 +485,14 @@ export interface ICoreKit { * - secp256k1Precompute: Provide a precomputed client for faster signing. Only works for ecdsa-secp256k1. * - keyTweak: Provide a bip340 key tweak. Only works for bip340. */ - sign( - data: Buffer, - opts?: { - hashed?: boolean; - secp256k1Precompute?: Secp256k1PrecomputedClient; - keyTweak?: BN; - } - ): Promise; + // sign( + // data: Buffer, + // opts?: { + // hashed?: boolean; + // secp256k1Precompute?: Secp256k1PrecomputedClient; + // keyTweak?: BN; + // } + // ): Promise; /** * WARNING: Use with caution. This will export the private signing key. @@ -503,7 +501,7 @@ export interface ICoreKit { * * For keytype ed25519, consider using _UNSAFE_exportTssEd25519Seed. */ - _UNSAFE_exportTssKey(): Promise; + _UNSAFE_exportTssKey(keyType: KeyType): Promise; /** * WARNING: Use with caution. This will export the private signing key. @@ -523,7 +521,6 @@ export interface SessionData { postboxKeyNodeIndexes?: number[]; factorKey: string; tssShareIndex: number; - tssPubKey: string; signatures: string[]; userInfo: UserInfo; } diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 7be699b7..3c7a7f05 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -19,7 +19,6 @@ import type { WasmLib as FrostWasmLibBip340 } from "@toruslabs/tss-frost-lib-bip import { SafeEventEmitter } from "@web3auth/auth"; import BN from "bn.js"; import bowser from "bowser"; -import { ec as EC } from "elliptic"; import { ERRORS, @@ -106,10 +105,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { [SIG_TYPE.BIP340]?: FrostWasmLibBip340; } = {}; - private _keyType: KeyType; - - private _sigType: SigType; - private atomicCallStackCounter: number = 0; private sessionSigGenerator: ISessionSigGenerator; @@ -127,8 +122,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { this.supportedCurveKeyTypes.add(tssLibItem.keyType as KeyType); this.supportedSigTypes.add(tssLibItem.sigType as SigType); }); - this._keyType = options.tssLibs[0].keyType as KeyType; - this._sigType = options.tssLibs[0].sigType as SigType; + this._tssLibs = options.tssLibs; if (!options.legacyFlag) { @@ -176,14 +170,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return this.tkey; } - get keyType(): KeyType { - return this._keyType; - } - - get sigType(): SigType { - return this._sigType; - } - get config(): Web3AuthOptionsWithDefaults { return this.options; } @@ -209,10 +195,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return this.sessionManager?.sessionId; } - get supportsAccountIndex(): boolean { - return this._sigType !== "ed25519"; - } - private get verifier(): string { if (this.state.userInfo?.aggregateVerifier) { return this.state.userInfo.aggregateVerifier; @@ -228,9 +210,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return this.options.uxMode === UX_MODE.REDIRECT; } - private get useClientGeneratedTSSKey(): boolean { - return this._sigType === "ed25519" && this.options.useClientGeneratedTSSKey === undefined ? true : !!this.options.useClientGeneratedTSSKey; - } + // private get useClientGeneratedTSSKey(): boolean { + // return this._sigType === "ed25519" && this.options.useClientGeneratedTSSKey === undefined ? true : !!this.options.useClientGeneratedTSSKey; + // } public setCustomSessionSigGenerator(sessionSigGenerator: ISessionSigGenerator) { this.sessionSigGenerator = sessionSigGenerator; @@ -240,28 +222,17 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return this.sessionSigGenerator.getSessionSigs(); } - public setTkeyType(tkeyType: KeyType) { - // check tkeyType is supported by tssLib - if (!this.supportedCurveKeyTypes.has(tkeyType)) throw CoreError.default("KeyType not supported, please provide valid tssLib"); - this._keyType = tkeyType; - } - - public setSigType(sigType: WEB3AUTH_SIG_TYPE) { - // check tkeyType is supported by tssLib - if (!this.supportedSigTypes.has(sigType)) throw CoreError.default("SigType not supported, please provide valid tssLib"); - this._sigType = sigType; - } - - public getTssShare(factorkey: BN, accountIndex?: number) { + public getTssShare(args: { keyType: KeyType; factorkey: BN; accountIndex?: number }) { + const { keyType, factorkey, accountIndex } = args; return this.tkey.getTSSShare(factorkey, { tssTag: TSS_TAG_DEFAULT, - keyType: this.keyType, + keyType, accountIndex: accountIndex === undefined ? this.state.accountIndex : accountIndex, }); } - public getTssData(args: { skipThrow: boolean; keyType?: KeyType } = { skipThrow: false }) { - const result = this.tkey.metadata.getTssData(args.keyType ?? this.keyType, TSS_TAG_DEFAULT); + public getTssData(args: { skipThrow?: boolean; keyType: KeyType }) { + const result = this.tkey.metadata.getTssData(args.keyType, TSS_TAG_DEFAULT); if (!result && !args.skipThrow) { throw CoreKitError.noMetadataFound(); } @@ -271,7 +242,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { // RecoverTssKey only valid for user that enable MFA where user has 2 type shares : // TssShareType.DEVICE and TssShareType.RECOVERY // if the factors key provided is the same type recovery will not works - public async _UNSAFE_recoverTssKey(factorKey: string[]) { + public async _UNSAFE_recoverTssKey(factorKey: string[], keyType: KeyType) { this.checkReady(); const factorKeyBN = new BN(factorKey[0], "hex"); const shareStore0 = await this.getFactorKeyMetadata(factorKeyBN); @@ -281,7 +252,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const tssIndexesBN: BN[] = []; for (let i = 0; i < factorKey.length; i++) { const factorKeyBNInput = new BN(factorKey[i], "hex"); - const { tssIndex, tssShare } = await this.getTssShare(factorKeyBNInput); + const { tssIndex, tssShare } = await this.getTssShare({ keyType, factorkey: factorKeyBNInput }); if (tssIndexes.includes(tssIndex)) { // reset instance before throw error await this.init(); @@ -292,30 +263,36 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { tssShares.push(tssShare); } - const tssCurve = getKeyCurve(this.keyType); + const tssCurve = getKeyCurve(keyType); const finalKey = lagrangeInterpolation(tssCurve, tssShares, tssIndexesBN); // reset instance after recovery completed await this.init(); return finalKey.toString("hex", 64); } + public getServiceProviderKeyType() { + // multicurve only support for secp256k1 torus/ sss + let keyType = KeyType.secp256k1; + + // incase of legacy flag, it will depends on the tsslib used + if (this.options.legacyFlag) { + if (this.supportedCurveKeyTypes.size > 1) { + throw CoreKitError.invalidConfig("Legacy flag is not supported for multiple curves"); + } + // return the only supported curve + keyType = this.supportedCurveKeyTypes.keys().next().value; + } + return keyType; + } + public async init(params: InitParams = { handleRedirectResult: true }): Promise { this.resetState(); if (params.rehydrate === undefined) params.rehydrate = true; - const nodeDetails = fetchLocalConfig(this.options.web3AuthNetwork, this.keyType); - - if (this._sigType === "ed25519" && this.options.useDKG) { - throw CoreKitError.invalidConfig("DKG is not supported for ed25519 signature type"); - } + const nodeDetails = fetchLocalConfig(this.options.web3AuthNetwork, KeyType.ed25519); // multicurve only support for secp256k1 torus/ sss - let keyType = KeyType.secp256k1; - if (this.options.legacyFlag) { - // check for added supported keyType - // if keyType is ed25519, - keyType = this.keyType; - } + const keyType = this.getServiceProviderKeyType(); this.torusSp = new TSSTorusServiceProvider({ customAuthArgs: { @@ -476,11 +453,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.invalidConfig("Cannot import TSS key and register SFA key at the same time."); } + const spKeyType = this.getServiceProviderKeyType(); try { // prefetch tss pub keys. const prefetchTssPubs = []; for (let i = 0; i < prefetchTssPublicKeys; i++) { - prefetchTssPubs.push(this.torusSp.getTSSPubKey(this.tkey.tssTag, i, this.keyType)); + prefetchTssPubs.push(this.torusSp.getTSSPubKey(this.tkey.tssTag, i, spKeyType)); } // get postbox key. @@ -506,8 +484,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.invalidConfig("Cannot register existing SFA key for v1 users, please contact web3auth support."); } const existingSFAKey = loginResponse.finalKeyData.privKey.padStart(64, "0"); + await this.setupTkey({ - providedImportKey: { [this._keyType]: existingSFAKey }, + providedImportKey: { [spKeyType]: existingSFAKey }, importingSFAKey: true, sfaLoginResponse: loginResponse, userInfo: { ...parseToken(idToken), verifier, verifierId }, @@ -581,8 +560,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { this.checkReady(); if (this.options.legacyFlag) { + const spKeyType = this.getServiceProviderKeyType(); // Check for existing curve in tssData for legacy mode - const tssData = this.getTssData({ skipThrow: true }); + const tssData = this.getTssData({ keyType: spKeyType, skipThrow: true }); if (!tssData) throw CoreKitError.default("Legacy mode only support single curve, please congfiure with correct keyType"); } @@ -609,7 +589,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } public setTssWalletIndex(accountIndex: number) { - this.updateState({ tssPubKey: this.getPubKey(false, accountIndex), accountIndex }); + this.updateState({ accountIndex }); } public getCurrentFactorKey(): IFactorKey { @@ -691,7 +671,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when getting tss factor public key."); } - const tssData = this.getTssData(); + const spKeyType = this.getServiceProviderKeyType(); + const tssData = this.getTssData({ keyType: spKeyType }); const factorPubsList = tssData.factorPubs; return factorPubsList.map((factorPub) => factorPub.toSEC1(factorKeyCurve, true).toString("hex")); }; @@ -739,17 +720,17 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { /** * Get public key point in SEC1 format. */ - public getPubKey(compressed: boolean = true, accountIndex?: number): Buffer { - const tssPubKey = this.getPubKeyPoint(accountIndex); - const tssCurve = getKeyCurve(this.keyType); + public getPubKey(keyType: KeyType, compressed: boolean = true, accountIndex?: number): Buffer { + const tssPubKey = this.getPubKeyPoint(keyType, accountIndex); + const tssCurve = getKeyCurve(keyType); return tssPubKey.toSEC1(tssCurve, compressed); } /** * Get public key point. */ - public getPubKeyPoint(accountIndex?: number): Point { - const tssPubKey = this.tkey.getTSSPub(this.keyType, TSS_TAG_DEFAULT, accountIndex === undefined ? this.state.accountIndex : accountIndex); + public getPubKeyPoint(keyType: KeyType, accountIndex?: number): Point { + const tssPubKey = this.tkey.getTSSPub(keyType, TSS_TAG_DEFAULT, accountIndex === undefined ? this.state.accountIndex : accountIndex); return tssPubKey; } @@ -759,12 +740,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { * Throws an error if signature type is not ed25519. */ public getPubKeyEd25519(): Buffer { - if (this._sigType !== "ed25519") { - throw CoreKitError.default(`getPubKeyEd25519 not supported for signature type ${this.sigType}`); + if (!this.supportedSigTypes.has(KeyType.ed25519)) { + throw CoreKitError.default(`ed25519 is not supported, please configure tssLib with ed25519 signature type `); } - const tssCurve = getKeyCurve(this.keyType); - const p = this.getPubKeyPoint().toEllipticPoint(tssCurve); + const tssCurve = getKeyCurve(KeyType.ed25519); + // ed25519 only support account index 0 ? + const p = this.getPubKeyPoint(KeyType.ed25519, 0).toEllipticPoint(tssCurve); return ed25519().keyFromPublic(p).getPublic(); } @@ -774,12 +756,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { * Throws an error if signature type is not bip340. */ public getPubKeyBip340(): Buffer { - if (this._sigType !== "bip340") { - throw CoreKitError.default(`getPubKeyBip340 not supported for signature type ${this.sigType}`); + if (!this.supportedSigTypes.has("bip340")) { + throw CoreKitError.default(`getPubKeyBip340 not supported , please configure tssLib with bip340 signature type `); } - const tssCurve = getKeyCurve(this.keyType); - const p = this.getPubKeyPoint().toEllipticPoint(tssCurve); + const tssCurve = getKeyCurve(KeyType.secp256k1); + const p = this.getPubKeyPoint(KeyType.secp256k1).toEllipticPoint(tssCurve); return p.getX().toBuffer("be", 32); } @@ -790,20 +772,23 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { }> { const { sessionSignatures } = params || {}; - await this.loadTssWasm(SIG_TYPE.ECDSA_SECP256K1); - const dklsWasm = this.wasmLib[SIG_TYPE.ECDSA_SECP256K1]; + const keyType = KeyType.secp256k1; + const sigType = SIG_TYPE.ECDSA_SECP256K1; + + await this.loadTssWasm(sigType); + const dklsWasm = this.wasmLib[sigType]; // PreSetup const { tssShareIndex } = this.state; - const tssPubKey = this.getPubKeyPoint(); + const tssPubKey = this.getPubKeyPoint(keyType); - const { torusNodeTSSEndpoints } = fetchLocalConfig(this.options.web3AuthNetwork, this.keyType); + const { torusNodeTSSEndpoints } = fetchLocalConfig(this.options.web3AuthNetwork, keyType); if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when signing."); } - const { tssShare } = await this.getTssShare(this.state.factorKey, 0); - const tssNonce = this.getTssNonce(); + const { tssShare } = await this.getTssShare({ keyType, factorkey: this.state.factorKey, accountIndex: 0 }); + const tssNonce = this.getTssNonce(keyType); if (!tssPubKey || !torusNodeTSSEndpoints) { throw CoreKitError.tssPublicKeyOrEndpointsMissing(); @@ -817,8 +802,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const clientIndex = parties - 1; // 1. setup // generate endpoints for servers - const tssData = this.getTssData(); - const { nodeIndexes } = await this.torusSp.getTSSPubKey(this.tKey.tssTag, tssData.tssNonce, this.keyType); + const tssData = this.getTssData({ keyType }); + const { nodeIndexes } = await this.torusSp.getTSSPubKey(this.tKey.tssTag, tssData.tssNonce, keyType); const { endpoints, tssWSEndpoints, @@ -872,39 +857,71 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { }; } - public async sign( - data: Buffer, - opts?: { - hashed?: boolean; - secp256k1Precompute?: Secp256k1PrecomputedClient; - keyTweak?: BN; + public async signECDSA(data: Uint8Array, opts: { hashed?: boolean; secp256k1Precompute?: Secp256k1PrecomputedClient }) { + const { hashed = false, secp256k1Precompute } = opts || {}; + + // TODO: replace buffer to uint8array + const sig = await this.sign_ECDSA_secp256k1(Buffer.from(data), hashed, secp256k1Precompute); + return Buffer.concat([sig.r, sig.s, Buffer.from([sig.v])]); + } + + public async signBip340(data: Uint8Array, opts?: { hashed?: boolean; keyTweak?: BN }) { + if (opts?.hashed) { + throw CoreKitError.default(`hashed data not supported for bip340`); } - ): Promise { - // this.wasmLib = await this.loadTssWasm(); - if (this._sigType === "ecdsa-secp256k1") { - if (opts?.keyTweak) { - throw CoreKitError.default("key tweaking not supported for ecdsa-secp256k1"); - } - const sig = await this.sign_ECDSA_secp256k1(data, opts?.hashed, opts?.secp256k1Precompute); - return Buffer.concat([sig.r, sig.s, Buffer.from([sig.v])]); - } else if (this._sigType === "ed25519" || this._sigType === "bip340") { - if (opts?.hashed) { - throw CoreKitError.default(`hashed data not supported for bip340`); - } else if (opts?.keyTweak && this._sigType !== "bip340") { - throw CoreKitError.default("key tweaking not supported for ed25519"); - } + await this.loadTssWasm(SIG_TYPE.BIP340); + const frostlib = this.wasmLib[SIG_TYPE.BIP340]; + if (!frostlib) { + throw CoreKitError.default(`frostlib not loaded for ed25519`); + } + return this.sign_frost({ data: Buffer.from(data), keyType: KeyType.secp256k1, sigType: SIG_TYPE.BIP340, frostlib, keyTweak: opts.keyTweak }); + } - return this.sign_frost(data, opts?.keyTweak); + public async signEd25519(data: Uint8Array, opts?: { hashed?: boolean }) { + if (opts?.hashed) { + throw CoreKitError.default(`hashed data not supported for bip340`); + } + await this.loadTssWasm(SIG_TYPE.ED25519); + const frostlib = this.wasmLib[SIG_TYPE.ED25519]; + if (!frostlib) { + throw CoreKitError.default(`frostlib not loaded for ed25519`); } - throw CoreKitError.default(`sign not supported for key type ${this.keyType}`); + return this.sign_frost({ data: Buffer.from(data), keyType: KeyType.ed25519, sigType: SIG_TYPE.ED25519, frostlib }); } + // public async sign( + // data: Buffer, + // opts?: { + // hashed?: boolean; + // secp256k1Precompute?: Secp256k1PrecomputedClient; + // keyTweak?: BN; + // } + // ): Promise { + // // this.wasmLib = await this.loadTssWasm(); + // if (this._sigType === "ecdsa-secp256k1") { + // if (opts?.keyTweak) { + // throw CoreKitError.default("key tweaking not supported for ecdsa-secp256k1"); + // } + // const sig = await this.sign_ECDSA_secp256k1(data, opts?.hashed, opts?.secp256k1Precompute); + // return Buffer.concat([sig.r, sig.s, Buffer.from([sig.v])]); + // } else if (this._sigType === "ed25519" || this._sigType === "bip340") { + // if (opts?.hashed) { + // throw CoreKitError.default(`hashed data not supported for bip340`); + // } else if (opts?.keyTweak && this._sigType !== "bip340") { + // throw CoreKitError.default("key tweaking not supported for ed25519"); + // } + + // return this.sign_frost(data, opts?.keyTweak); + // } + // throw CoreKitError.default(`sign not supported for key type ${this.keyType}`); + // } // mutation function async deleteFactor(factorPub: Point, factorKey?: BNString): Promise { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when deleting a factor."); } - const tssData = this.getTssData(); + const spKeyType = this.getServiceProviderKeyType(); + const tssData = this.getTssData({ keyType: spKeyType }); if (!tssData.factorPubs) { throw CoreKitError.factorPubsMissing(); } @@ -962,13 +979,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { public getKeyDetails(): MPCKeyDetails { this.checkReady(); - const tssData = this.getTssData({ skipThrow: true }); const tkeyDetails = this.tKey.getKeyDetails(); - const tssCurve = getKeyCurve(this.keyType); - // TODO: fix me, should remove tssPubKey from state - const tssPubKey = this.state.tssPubKey ? Point.fromSEC1(tssCurve, this.state.tssPubKey.toString("hex")) : undefined; - const factors = tssData?.factorPubs ? tssData.factorPubs : []; + const factors = this.getTssFactorPub(); const keyDetails: MPCKeyDetails = { // use tkey's for now requiredFactors: tkeyDetails.requiredShares, @@ -976,8 +989,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { totalFactors: factors.length + 1, shareDescriptions: this.tKey.getMetadata().getShareDescription(), metadataPubKey: tkeyDetails.pubKey, - tssPubKey, - keyType: this.keyType, + supportedKeyType: Array.from(this.supportedCurveKeyTypes), }; return keyDetails; } @@ -1043,7 +1055,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { * * For signature type ed25519, consider using _UNSAFE_exportTssEd25519Seed. */ - public async _UNSAFE_exportTssKey(): Promise { + // TODO : should return all keyType final keys? + public async _UNSAFE_exportTssKey(keyType: KeyType): Promise { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when exporting tss key."); } @@ -1054,12 +1067,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const exportTssKey0 = await this.tKey._UNSAFE_exportTssKey({ factorKey: this.state.factorKey, authSignatures: this.state.signatures, - keyType: this.keyType, + keyType, tssTag: TSS_TAG_DEFAULT, }); const accountNonce = this.getAccountNonce(); - const tssCurve = getKeyCurve(this.keyType); + const tssCurve = getKeyCurve(keyType); const tssKey = exportTssKey0.add(accountNonce).umod(tssCurve.n); return tssKey.toString("hex", FIELD_ELEMENT_HEX_LEN); @@ -1072,7 +1085,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { * flow has been used. */ public async _UNSAFE_exportTssEd25519Seed(): Promise { - if (this._sigType !== "ed25519") { + if (!this.supportedSigTypes.has("ed25519")) { throw CoreKitError.default("Wrong signature type. Method can only be used when signature type is ed25519."); } if (!this.state.factorKey) throw CoreKitError.factorKeyNotPresent("factorKey not present in state when exporting tss ed25519 seed."); @@ -1125,18 +1138,20 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { sp.verifierName = userInfo.aggregateVerifier || userInfo.verifier; } + const spKeyType = this.getServiceProviderKeyType(); const existingUser = await this.isMetadataPresent(this.state.postBoxKey); const importKey = providedImportKey ?? {}; if (!existingUser) { - if (!importKey && this.useClientGeneratedTSSKey) { - if (this.keyType === KeyType.ed25519) { + // if (!importKey && this.useClientGeneratedTSSKey) { + if (!importKey) { + if (spKeyType === KeyType.ed25519) { const k = generateEd25519Seed(); importKey.ed25519 = k.toString("hex"); - } else if (this.keyType === KeyType.secp256k1) { + } else if (spKeyType === KeyType.secp256k1) { const k = secp256k1.genKeyPair().getPrivate(); importKey.secp256k1 = scalarBNToBufferSEC1(k).toString("hex"); } else { - throw CoreKitError.default(`Unsupported key type and sig type combination: ${this.keyType}, ${this._sigType}`); + throw CoreKitError.default(`Unsupported key type and sig type combination `); } } if (importingSFAKey && sfaLoginResponse && sfaLoginResponse.metadata.upgraded) { @@ -1185,8 +1200,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { // ); // } - private getTssNonce(): number { - const tssData = this.getTssData(); + private getTssNonce(keyType: KeyType): number { + const tssData = this.getTssData({ keyType }); if (tssData.tssNonce === undefined) { throw CoreKitError.tssNoncesMissing(`tssNonce not present for tag ${this.tKey.tssTag}`); } @@ -1210,21 +1225,16 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const deviceTSSIndex = TssShareType.DEVICE; const factorPub = getPubKeyPoint(factorKey, factorKeyCurve); - const ec = new EC(this.keyType); - const deviceTSSShare = ec.genKeyPair().getPrivate(); await this.tKey.initialize(); // only consider 2 types of curve, will change the logic in the future if there are more key types curves - // if both keyType library is avaiable, initialize secp256k1 first as secp256k1 is initialize offline - if (this.supportedCurveKeyTypes.has(KeyType.secp256k1)) { const importTssBuf = importTssKey.secp256k1 ? Buffer.from(importTssKey.secp256k1, "hex") : undefined; // check if key is in the tsslib and keytype exists await this.tKey.initializeTss({ importKey: importTssBuf, factorPub, - deviceTSSShare, deviceTSSIndex, tssKeyType: KeyType.secp256k1, serverOpts: { @@ -1278,8 +1288,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { await this.tKey.initialize({ neverInitializeNewKey: true }); if (this.options.legacyFlag) { + const spKeyType = this.getServiceProviderKeyType(); // Check for existing curve in tssData for legacy mode - const tssData = this.getTssData({ skipThrow: true }); + const tssData = this.getTssData({ keyType: spKeyType, skipThrow: true }); if (!tssData) throw CoreKitError.default("Legacy mode only support single curve, please congfiure with correct keyType"); } @@ -1339,12 +1350,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { }); } + const spKeyType = this.getServiceProviderKeyType(); // Read tss meta data. - const { tssIndex: tssShareIndex } = await this.getTssShare(factorKey); - const tssCurve = getKeyCurve(this._keyType); - const tssPubKey = this.tKey.getTSSPub(this.keyType, TSS_TAG_DEFAULT).toSEC1(tssCurve, false); - - this.updateState({ tssShareIndex, tssPubKey, factorKey }); + const { tssIndex: tssShareIndex } = await this.getTssShare({ keyType: spKeyType, factorkey: factorKey }); + this.updateState({ tssShareIndex, factorKey }); await this.createSession(); } @@ -1375,16 +1384,11 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { await this.tKey.inputShareStoreSafe(factorKeyMetadata, true); await this.tKey.reconstructKey(); - const tssCurve = getKeyCurve(this._keyType); - this.updateState({ factorKey: new BN(result.factorKey, "hex"), postBoxKey, postboxKeyNodeIndexes: result.postboxKeyNodeIndexes || [], tssShareIndex: result.tssShareIndex, - // still need tssPubkey on the state? - // should compute from tkey as we support the account index - tssPubKey: this.tkey.getTSSPub(this.keyType, TSS_TAG_DEFAULT).toSEC1(tssCurve, false), signatures: result.signatures, userInfo: result.userInfo, }); @@ -1404,12 +1408,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { try { const sessionId = SessionManager.generateRandomSessionKey(); this.sessionManager.sessionId = sessionId; - const { postBoxKey, factorKey, userInfo, tssShareIndex, tssPubKey, postboxKeyNodeIndexes } = this.state; + const { postBoxKey, factorKey, userInfo, tssShareIndex, postboxKeyNodeIndexes } = this.state; if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when creating session."); } - const { tssShare } = await this.getTssShare(this.state.factorKey); - if (!postBoxKey || !factorKey || !tssShare || !tssPubKey || !userInfo) { + const spKeyType = this.getServiceProviderKeyType(); + const { tssShare } = await this.getTssShare({ keyType: spKeyType, factorkey: this.state.factorKey }); + if (!postBoxKey || !factorKey || !tssShare || !userInfo) { throw CoreKitError.userNotLoggedIn(); } const sessionSigs = this.state.signatures; @@ -1418,7 +1423,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { postboxKeyNodeIndexes: postboxKeyNodeIndexes || [], factorKey: factorKey?.toString("hex"), tssShareIndex: tssShareIndex as number, - tssPubKey: Buffer.from(tssPubKey).toString("hex"), signatures: sessionSigs, userInfo, }; @@ -1465,7 +1469,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { */ private async copyOrCreateShare(newFactorTSSIndex: number, newFactorPub: Point) { this.checkReady(); - const tssData = this.getTssData(); + const spKeyType = this.getServiceProviderKeyType(); + const tssData = this.getTssData({ keyType: spKeyType }); if (!tssData.factorPubs || !Array.isArray(tssData.factorPubs)) { throw CoreKitError.factorPubsMissing("'factorPubs' is missing in the metadata. Failed to copy factor public key."); } @@ -1543,7 +1548,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { additionalMetadata = {}; } - const { tssIndex } = await this.getTssShare(factorKey); + const spKeyType = this.getServiceProviderKeyType(); + const { tssIndex } = await this.getTssShare({ keyType: spKeyType, factorkey: factorKey }); const factorPoint = getPubKeyPoint(factorKey, factorKeyCurve); const factorPub = factorPoint.toSEC1(factorKeyCurve, true).toString("hex"); @@ -1642,8 +1648,15 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } } - private async sign_frost(data: Buffer, keyTweak?: BN): Promise { - const nodeDetails = fetchLocalConfig(this.options.web3AuthNetwork, this.keyType, this._sigType); + private async sign_frost(args: { + data: Buffer; + keyTweak?: BN; + keyType: KeyType; + sigType: WEB3AUTH_SIG_TYPE; + frostlib: FrostWasmLibEd25519 | FrostWasmLibBip340; + }): Promise { + const { data, keyTweak, keyType, sigType, frostlib } = args; + const nodeDetails = fetchLocalConfig(this.options.web3AuthNetwork, keyType, sigType); if (!nodeDetails.torusNodeTSSEndpoints) { throw CoreKitError.default("could not fetch tss node endpoints"); } @@ -1660,29 +1673,28 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { // Derive share coefficients for flat hierarchy. const ec = (() => { - if (this.keyType === KeyType.secp256k1) { + if (keyType === KeyType.secp256k1) { return new Secp256k1Curve(); - } else if (this.keyType === KeyType.ed25519) { + } else if (keyType === KeyType.ed25519) { return new Ed25519Curve(); } - throw CoreKitError.default(`key type ${this.keyType} not supported with FROST signing`); + throw CoreKitError.default(`key type ${keyType} not supported with FROST signing`); })(); const { serverCoefficients, clientCoefficient } = deriveShareCoefficients(ec, serverXCoords, clientXCoord, this.state.tssShareIndex); // Get pub key. - const tssPubKey = this.getPubKey(); - const tssPubKeyPoint = ec.keyFromPublic(tssPubKey).getPublic(); + const tssPubKeyPoint = this.getPubKeyPoint(keyType).toEllipticPoint(ec); // Get client key share and adjust by coefficient. - if (this._sigType === "ed25519" && this.state.accountIndex !== 0) { + if (sigType === "ed25519" && this.state.accountIndex !== 0) { throw CoreKitError.default("Account index not supported for ed25519"); } - const { tssShare } = await this.getTssShare(this.state.factorKey); + const { tssShare } = await this.getTssShare({ keyType, factorkey: this.state.factorKey }); const clientShareAdjusted = tssShare.mul(clientCoefficient).umod(ec.n); const clientShareAdjustedHex = ec.scalarToBuffer(clientShareAdjusted, Buffer).toString("hex"); // Generate session identifier. - const tssNonce = this.getTssNonce(); + const tssNonce = this.getTssNonce(keyType); const sessionNonce = generateSessionNonce(); const session = getSessionId(this.verifier, this.verifierId, this.tKey.tssTag, tssNonce, sessionNonce); @@ -1692,9 +1704,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const serverCoefficientsHex = serverCoefficients.map((c) => ec.scalarToBuffer(c, Buffer).toString("hex")); const authSignatures = await this.getSessionSignatures(); - await this.loadTssWasm(this._sigType); - - const frostlib = this.sigType === SIG_TYPE.BIP340 ? this.wasmLib[SIG_TYPE.BIP340] : this.wasmLib[SIG_TYPE.ED25519]; const signature = await signFrost( frostlib, session, @@ -1725,6 +1734,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } if (sigType === SIG_TYPE.ED25519 || sigType === SIG_TYPE.BIP340) this.wasmLib[sigType] = (await matchLibs?.load()) as FrostWasmLibEd25519; } - return this.wasmLib; + return this.wasmLib[sigType]; } } diff --git a/tests/multiCurveTest.ts b/tests/multiCurveTest.ts index e4433bcb..f3f0d258 100644 --- a/tests/multiCurveTest.ts +++ b/tests/multiCurveTest.ts @@ -45,32 +45,23 @@ describe("multiCurveTest", () => { const testAllSigning = async (instance: Web3AuthMPCCoreKit) => { const message = "message to sign"; - - instance.setTkeyType(KeyType.secp256k1) - instance.setSigType("ecdsa-secp256k1") - const hash = keccak_256(message); - const result = await instance.sign(Buffer.from(hash), {hashed: true}) - + const result = await instance.signECDSA(Buffer.from(hash), {hashed: true}) const {r, s } = sigToRSV(result); - // new secp256k1.Signature() const validsecp256k1 = secp256k1.verify({ r: bytesToNumberBE(r), s: bytesToNumberBE(s), - }, bytesToHex(hash), bytesToHex(instance.getPubKey(false))) + }, bytesToHex(hash), bytesToHex(instance.getPubKey(KeyType.secp256k1, false))) expect(validsecp256k1).eq(true); - instance.setSigType("bip340"); - const result2 = await instance.sign( Buffer.from(utf8ToBytes(message)), {hashed: false}) + const result2 = await instance.signBip340( Buffer.from(utf8ToBytes(message)), {hashed: false}) const validb340 = bip340.verify(bytesToHex(result2), bytesToHex(utf8ToBytes(message)), bytesToHex(instance.getPubKeyBip340())); expect(validb340).eq(true); - instance.setSigType("ed25519") - instance.setTkeyType(KeyType.ed25519) - const result3 = await instance.sign(Buffer.from(message), { hashed: false }) + const result3 = await instance.signEd25519(Buffer.from(message), { hashed: false }) const valided25519 = ed25519.verify(bytesToHex(result3), bytesToHex(Buffer.from(message)), bytesToHex( new Uint8Array(instance.getPubKeyEd25519()) ) ) expect(valided25519).eq(true); From 69532877ba9f9a0848873bf0067aee1e511b18fe Mon Sep 17 00:00:00 2001 From: ieow Date: Wed, 12 Feb 2025 15:58:06 +0800 Subject: [PATCH 05/16] fix: allow tsslib to be added later --- src/interfaces.ts | 4 +-- src/mpcCoreKit.ts | 83 ++++++++++++++++++++++++++++------------------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/src/interfaces.ts b/src/interfaces.ts index 74c682d4..39d13bc9 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -201,9 +201,9 @@ export interface Web3AuthOptions { web3AuthClientId: string; /** - * The threshold signing library to use. + * The supported curve key type. */ - tssLibs: TssLibType[]; + supportedKeyTypes: KeyType[]; /** * @defaultValue `false` diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 3c7a7f05..20f4ad94 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -97,7 +97,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { private ready = false; - private _tssLibs: TssLibType[]; + private _tssLibs: TssLibType[] = []; private wasmLib: { [SIG_TYPE.ECDSA_SECP256K1]?: DKLSWasmLib; @@ -118,12 +118,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.clientIdInvalid(); } - options.tssLibs.forEach((tssLibItem) => { - this.supportedCurveKeyTypes.add(tssLibItem.keyType as KeyType); - this.supportedSigTypes.add(tssLibItem.sigType as SigType); - }); - - this._tssLibs = options.tssLibs; + if (options.supportedKeyTypes.length === 0) { + throw CoreKitError.invalidConfig("No supported key types provided"); + } + this.supportedCurveKeyTypes = new Set(options.supportedKeyTypes); if (!options.legacyFlag) { options.legacyFlag = false; @@ -214,6 +212,30 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { // return this._sigType === "ed25519" && this.options.useClientGeneratedTSSKey === undefined ? true : !!this.options.useClientGeneratedTSSKey; // } + /** + * The threshold signing library to use. + */ + public addTssLibs(tssLibs: TssLibType[], force = false) { + for (const tssLib of tssLibs) { + if (!this.supportedCurveKeyTypes.has(tssLib.keyType as KeyType)) { + throw CoreKitError.invalidConfig( + `Tsslib key type: ${tssLib.keyType} is not supported, please reconfigure corekit with supported curves keytype` + ); + } + if (this.supportedSigTypes.has(tssLib.sigType as WEB3AUTH_SIG_TYPE)) { + if (force) { + this._tssLibs = this._tssLibs.filter((t) => t.sigType !== tssLib.sigType); + this._tssLibs.push(tssLib); + } else { + log.warn(`Tsslib sig type: ${tssLib.sigType} is already exists, library is not appended`); + } + continue; + } + this.supportedSigTypes.add(tssLib.sigType as WEB3AUTH_SIG_TYPE); + this._tssLibs.push(tssLib); + } + } + public setCustomSessionSigGenerator(sessionSigGenerator: ISessionSigGenerator) { this.sessionSigGenerator = sessionSigGenerator; } @@ -858,6 +880,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } public async signECDSA(data: Uint8Array, opts: { hashed?: boolean; secp256k1Precompute?: Secp256k1PrecomputedClient }) { + if (!this.supportedCurveKeyTypes.has(KeyType.secp256k1)) { + throw CoreKitError.default(`secp256k1 KeyTYpe is not supported, please configure secp256k1 curve key type `); + } + if (!this.supportedSigTypes.has(SIG_TYPE.ECDSA_SECP256K1)) { + throw CoreKitError.default(`ECDSA_SECP256K1 is not supported, please configure tssLib with ECDSA_SECP256K1 signature type `); + } const { hashed = false, secp256k1Precompute } = opts || {}; // TODO: replace buffer to uint8array @@ -866,6 +894,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } public async signBip340(data: Uint8Array, opts?: { hashed?: boolean; keyTweak?: BN }) { + if (!this.supportedCurveKeyTypes.has(KeyType.secp256k1)) { + throw CoreKitError.default(`secp256k1 KeyTYpe is not supported, please configure secp256k1 curve key type `); + } + if (!this.supportedSigTypes.has(SIG_TYPE.BIP340)) { + throw CoreKitError.default(`BIP340 is not supported, please configure tssLib with BIP340 signature type `); + } + if (opts?.hashed) { throw CoreKitError.default(`hashed data not supported for bip340`); } @@ -878,6 +913,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } public async signEd25519(data: Uint8Array, opts?: { hashed?: boolean }) { + if (!this.supportedCurveKeyTypes.has(KeyType.ed25519)) { + throw CoreKitError.default(`ed25519 KeyTYpe is not supported, please configure ed25519 curve key type `); + } + if (!this.supportedSigTypes.has(SIG_TYPE.ED25519)) { + throw CoreKitError.default(`ed25519 is not supported, please configure tssLib with ed25519 signature type `); + } + if (opts?.hashed) { throw CoreKitError.default(`hashed data not supported for bip340`); } @@ -888,34 +930,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } return this.sign_frost({ data: Buffer.from(data), keyType: KeyType.ed25519, sigType: SIG_TYPE.ED25519, frostlib }); } - // public async sign( - // data: Buffer, - // opts?: { - // hashed?: boolean; - // secp256k1Precompute?: Secp256k1PrecomputedClient; - // keyTweak?: BN; - // } - // ): Promise { - // // this.wasmLib = await this.loadTssWasm(); - // if (this._sigType === "ecdsa-secp256k1") { - // if (opts?.keyTweak) { - // throw CoreKitError.default("key tweaking not supported for ecdsa-secp256k1"); - // } - // const sig = await this.sign_ECDSA_secp256k1(data, opts?.hashed, opts?.secp256k1Precompute); - // return Buffer.concat([sig.r, sig.s, Buffer.from([sig.v])]); - // } else if (this._sigType === "ed25519" || this._sigType === "bip340") { - // if (opts?.hashed) { - // throw CoreKitError.default(`hashed data not supported for bip340`); - // } else if (opts?.keyTweak && this._sigType !== "bip340") { - // throw CoreKitError.default("key tweaking not supported for ed25519"); - // } - - // return this.sign_frost(data, opts?.keyTweak); - // } - // throw CoreKitError.default(`sign not supported for key type ${this.keyType}`); - // } // mutation function + async deleteFactor(factorPub: Point, factorKey?: BNString): Promise { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when deleting a factor."); From 8e7fde9fdfac01e74d9adbba4e6050ee7d2b41fb Mon Sep 17 00:00:00 2001 From: ieow Date: Wed, 12 Feb 2025 16:07:21 +0800 Subject: [PATCH 06/16] fix: multicurve tests --- tests/multiCurveTest.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/multiCurveTest.ts b/tests/multiCurveTest.ts index f3f0d258..a1cb5a98 100644 --- a/tests/multiCurveTest.ts +++ b/tests/multiCurveTest.ts @@ -36,7 +36,7 @@ describe("multiCurveTest", () => { web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode: "nodejs", - tssLibs : [dklslib, frostLib, frostBip340lib], + supportedKeyTypes: [KeyType.secp256k1, KeyType.ed25519], storage: storageInstance, manualSync, }); @@ -46,6 +46,7 @@ describe("multiCurveTest", () => { const message = "message to sign"; const hash = keccak_256(message); + instance.addTssLibs([dklslib]); const result = await instance.signECDSA(Buffer.from(hash), {hashed: true}) const {r, s } = sigToRSV(result); @@ -55,12 +56,14 @@ describe("multiCurveTest", () => { }, bytesToHex(hash), bytesToHex(instance.getPubKey(KeyType.secp256k1, false))) expect(validsecp256k1).eq(true); + instance.addTssLibs([frostBip340lib]); const result2 = await instance.signBip340( Buffer.from(utf8ToBytes(message)), {hashed: false}) const validb340 = bip340.verify(bytesToHex(result2), bytesToHex(utf8ToBytes(message)), bytesToHex(instance.getPubKeyBip340())); expect(validb340).eq(true); + instance.addTssLibs([frostLib]); const result3 = await instance.signEd25519(Buffer.from(message), { hashed: false }) const valided25519 = ed25519.verify(bytesToHex(result3), bytesToHex(Buffer.from(message)), bytesToHex( new Uint8Array(instance.getPubKeyEd25519()) ) ) expect(valided25519).eq(true); From 7e699d27402109c5e131533991310cc84cc48bef Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 13 Feb 2025 16:09:15 +0800 Subject: [PATCH 07/16] fix: stable with most test passed --- package-lock.json | 2 +- src/mpcCoreKit.ts | 91 ++++++++++++++++++++----------- src/utils.ts | 32 +++++++++++ tests/backwardCompatible.spec.ts | 26 ++++----- tests/bip340.spec.ts | 48 ++++++++++------- tests/ed25519.spec.ts | 25 +++++---- tests/factors.spec.ts | 24 +++++---- tests/gating.spec.ts | 4 +- tests/importRecovery.spec.ts | 71 ++++++++++++------------ tests/login.spec.ts | 44 ++++++++------- tests/multiCurveTest.ts | 1 - tests/securityQuestion.spec.ts | 18 ++++--- tests/sessionTime.spec.ts | 4 +- tests/setup.ts | 45 +++++++++++++--- tests/sfaImport.spec.ts | 92 ++++++++++++++++++-------------- 15 files changed, 327 insertions(+), 200 deletions(-) diff --git a/package-lock.json b/package-lock.json index 933e5d5a..bda8a48b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3906,7 +3906,7 @@ "node_modules/@tkey/tss": { "version": "15.2.1-alpha.0", "resolved": "file:../tkey/packages/tss/tkey-tss-15.2.1-alpha.0.tgz", - "integrity": "sha512-qc+aZ3PnAkbUZlcbKAcFJ5rVmnqZuJnFhCp/y031BOJWmCH+Lw4wwlSAqrzH9Z9NEi+D7QnOS8r2eay4dTd56g==", + "integrity": "sha512-PWETbhENWKAkRacaKE1ftP+X74XnXIn6vw5COvKBlX2ClZMrZwfUYr/nS7McX3zNhfhHkDMHjarij++QV5Vnog==", "license": "ISC", "dependencies": { "@tkey/common-types": "^15.2.1-alpha.0", diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 20f4ad94..703ac830 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -212,6 +212,14 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { // return this._sigType === "ed25519" && this.options.useClientGeneratedTSSKey === undefined ? true : !!this.options.useClientGeneratedTSSKey; // } + public getSupportedSigTypes(): Array { + return Array.from(this.supportedSigTypes); + } + + public getSupportedCurveKeyTypes(): Array { + return Array.from(this.supportedCurveKeyTypes); + } + /** * The threshold signing library to use. */ @@ -314,7 +322,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const nodeDetails = fetchLocalConfig(this.options.web3AuthNetwork, KeyType.ed25519); // multicurve only support for secp256k1 torus/ sss - const keyType = this.getServiceProviderKeyType(); + const spKeyType = this.getServiceProviderKeyType(); this.torusSp = new TSSTorusServiceProvider({ customAuthArgs: { @@ -325,7 +333,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { redirectPathName: this.options.redirectPathName, locationReplaceOnRedirect: true, serverTimeOffset: this.options.serverTimeOffset, - keyType, + keyType: spKeyType, useDkg: this.options.useDKG, }, }); @@ -475,12 +483,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.invalidConfig("Cannot import TSS key and register SFA key at the same time."); } - const spKeyType = this.getServiceProviderKeyType(); + const fisrtKeyType = this.getSupportedCurveKeyTypes()[0]; try { // prefetch tss pub keys. const prefetchTssPubs = []; for (let i = 0; i < prefetchTssPublicKeys; i++) { - prefetchTssPubs.push(this.torusSp.getTSSPubKey(this.tkey.tssTag, i, spKeyType)); + prefetchTssPubs.push(this.torusSp.getTSSPubKey(this.tkey.tssTag, i, fisrtKeyType)); } // get postbox key. @@ -505,10 +513,14 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (loginResponse.metadata.typeOfUser === "v1") { throw CoreKitError.invalidConfig("Cannot register existing SFA key for v1 users, please contact web3auth support."); } + const spKeyType = this.getServiceProviderKeyType(); + if (!this.supportedCurveKeyTypes.has(spKeyType)) { + throw CoreKitError.invalidConfig("Cannot register existing SFA key for secp256k1 users to ed25519, please contact web3auth support."); + } const existingSFAKey = loginResponse.finalKeyData.privKey.padStart(64, "0"); await this.setupTkey({ - providedImportKey: { [spKeyType]: existingSFAKey }, + providedImportKey: { [fisrtKeyType]: existingSFAKey }, importingSFAKey: true, sfaLoginResponse: loginResponse, userInfo: { ...parseToken(idToken), verifier, verifierId }, @@ -693,8 +705,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when getting tss factor public key."); } - const spKeyType = this.getServiceProviderKeyType(); - const tssData = this.getTssData({ keyType: spKeyType }); + const firstKeyType = this.getSupportedCurveKeyTypes()[0]; + const tssData = this.getTssData({ keyType: firstKeyType }); const factorPubsList = tssData.factorPubs; return factorPubsList.map((factorPub) => factorPub.toSEC1(factorKeyCurve, true).toString("hex")); }; @@ -879,7 +891,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { }; } - public async signECDSA(data: Uint8Array, opts: { hashed?: boolean; secp256k1Precompute?: Secp256k1PrecomputedClient }) { + public async signECDSA(data: Uint8Array, opts?: { hashed?: boolean; secp256k1Precompute?: Secp256k1PrecomputedClient }) { if (!this.supportedCurveKeyTypes.has(KeyType.secp256k1)) { throw CoreKitError.default(`secp256k1 KeyTYpe is not supported, please configure secp256k1 curve key type `); } @@ -909,7 +921,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!frostlib) { throw CoreKitError.default(`frostlib not loaded for ed25519`); } - return this.sign_frost({ data: Buffer.from(data), keyType: KeyType.secp256k1, sigType: SIG_TYPE.BIP340, frostlib, keyTweak: opts.keyTweak }); + return this.sign_frost({ data: Buffer.from(data), keyType: KeyType.secp256k1, sigType: SIG_TYPE.BIP340, frostlib, keyTweak: opts?.keyTweak }); } public async signEd25519(data: Uint8Array, opts?: { hashed?: boolean }) { @@ -937,8 +949,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when deleting a factor."); } - const spKeyType = this.getServiceProviderKeyType(); - const tssData = this.getTssData({ keyType: spKeyType }); + const firstKeyType = this.getSupportedCurveKeyTypes()[0]; + const tssData = this.getTssData({ keyType: firstKeyType }); if (!tssData.factorPubs) { throw CoreKitError.factorPubsMissing(); } @@ -1155,20 +1167,22 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { sp.verifierName = userInfo.aggregateVerifier || userInfo.verifier; } - const spKeyType = this.getServiceProviderKeyType(); const existingUser = await this.isMetadataPresent(this.state.postBoxKey); const importKey = providedImportKey ?? {}; if (!existingUser) { // if (!importKey && this.useClientGeneratedTSSKey) { - if (!importKey) { - if (spKeyType === KeyType.ed25519) { - const k = generateEd25519Seed(); - importKey.ed25519 = k.toString("hex"); - } else if (spKeyType === KeyType.secp256k1) { - const k = secp256k1.genKeyPair().getPrivate(); - importKey.secp256k1 = scalarBNToBufferSEC1(k).toString("hex"); - } else { - throw CoreKitError.default(`Unsupported key type and sig type combination `); + const keyTypes = this.getSupportedCurveKeyTypes(); + for (const keyType of keyTypes) { + if (!importKey[keyType]) { + if (keyType === KeyType.ed25519) { + const k = generateEd25519Seed(); + importKey.ed25519 = k.toString("hex"); + } else if (keyType === KeyType.secp256k1) { + const k = secp256k1.genKeyPair().getPrivate(); + importKey.secp256k1 = scalarBNToBufferSEC1(k).toString("hex"); + } else { + throw CoreKitError.default(`Unsupported key type and sig type combination `); + } } } if (importingSFAKey && sfaLoginResponse && sfaLoginResponse.metadata.upgraded) { @@ -1259,12 +1273,25 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { authSignatures: this.state.signatures, }, }); - } - if (this.supportedCurveKeyTypes.has(KeyType.ed25519)) { + + if (this.supportedCurveKeyTypes.has(KeyType.ed25519)) { + const importTssBufEd25519 = importTssKey.ed25519 ? Buffer.from(importTssKey.ed25519, "hex") : undefined; + // check if key is in the tsslib and keytype exists + await this.tKey.initializeTss({ + importKey: importTssBufEd25519, + tssKeyType: KeyType.ed25519, + serverOpts: { + // selectedServers: [], + authSignatures: this.state.signatures, + }, + }); + } + } else { const importTssBuf = importTssKey.ed25519 ? Buffer.from(importTssKey.ed25519, "hex") : undefined; - // check if key is in the tsslib and keytype exists await this.tKey.initializeTss({ importKey: importTssBuf, + factorPub, + deviceTSSIndex, tssKeyType: KeyType.ed25519, serverOpts: { // selectedServers: [], @@ -1367,9 +1394,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { }); } - const spKeyType = this.getServiceProviderKeyType(); + const firstKeyType = this.getSupportedCurveKeyTypes()[0]; // Read tss meta data. - const { tssIndex: tssShareIndex } = await this.getTssShare({ keyType: spKeyType, factorkey: factorKey }); + const { tssIndex: tssShareIndex } = await this.getTssShare({ keyType: firstKeyType, factorkey: factorKey }); this.updateState({ tssShareIndex, factorKey }); await this.createSession(); @@ -1429,8 +1456,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when creating session."); } - const spKeyType = this.getServiceProviderKeyType(); - const { tssShare } = await this.getTssShare({ keyType: spKeyType, factorkey: this.state.factorKey }); + const firstKeyType = this.getSupportedCurveKeyTypes()[0]; + const { tssShare } = await this.getTssShare({ keyType: firstKeyType, factorkey: this.state.factorKey }); if (!postBoxKey || !factorKey || !tssShare || !userInfo) { throw CoreKitError.userNotLoggedIn(); } @@ -1486,8 +1513,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { */ private async copyOrCreateShare(newFactorTSSIndex: number, newFactorPub: Point) { this.checkReady(); - const spKeyType = this.getServiceProviderKeyType(); - const tssData = this.getTssData({ keyType: spKeyType }); + const firstKeyType = this.getSupportedCurveKeyTypes()[0]; + const tssData = this.getTssData({ keyType: firstKeyType }); if (!tssData.factorPubs || !Array.isArray(tssData.factorPubs)) { throw CoreKitError.factorPubsMissing("'factorPubs' is missing in the metadata. Failed to copy factor public key."); } @@ -1565,8 +1592,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { additionalMetadata = {}; } - const spKeyType = this.getServiceProviderKeyType(); - const { tssIndex } = await this.getTssShare({ keyType: spKeyType, factorkey: factorKey }); + const firstKeyType = this.getSupportedCurveKeyTypes()[0]; + const { tssIndex } = await this.getTssShare({ keyType: firstKeyType, factorkey: factorKey }); const factorPoint = getPubKeyPoint(factorKey, factorKeyCurve); const factorPub = factorPoint.toSEC1(factorKeyCurve, true).toString("hex"); diff --git a/src/utils.ts b/src/utils.ts index 43179a35..74b6de28 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -211,5 +211,37 @@ export function makeEthereumSigner(kit: CoreKitSigner): EthereumSigner { }; } +// export function makeBip340Signer(kit: CoreKitSigner): EthereumSigner { +// if (kit.keyType !== KeyType.secp256k1) { +// throw new Error(`Invalid key type: expected secp256k1, got ${kit.keyType}`); +// } +// return { +// sign: async (msgHash: Buffer) => { +// const sig = await kit.sign(msgHash, { hashed: true }); +// return sigToRSV(sig); +// }, +// getPublic: async () => { +// const pk = Point.fromSEC1(secp256k1, kit.getPubKey().toString("hex")); +// return pk.toSEC1(secp256k1).subarray(1); +// }, +// }; +// } + +export function makeEd25519Signer(kit: CoreKitSigner): EthereumSigner { + if (kit.keyType !== KeyType.secp256k1) { + throw new Error(`Invalid key type: expected secp256k1, got ${kit.keyType}`); + } + return { + sign: async (msgHash: Buffer) => { + const sig = await kit.sign(msgHash, { hashed: true }); + return sigToRSV(sig); + }, + getPublic: async () => { + const pk = Point.fromSEC1(secp256k1, kit.getPubKey().toString("hex")); + return pk.toSEC1(secp256k1).subarray(1); + }, + }; +} + export const log = loglevel.getLogger("mpc-core-kit"); log.disableAll(); diff --git a/tests/backwardCompatible.spec.ts b/tests/backwardCompatible.spec.ts index 65084bcf..0c1b41e9 100644 --- a/tests/backwardCompatible.spec.ts +++ b/tests/backwardCompatible.spec.ts @@ -1,7 +1,7 @@ import assert from "node:assert"; import test from "node:test"; -import { EllipticPoint } from "@tkey/common-types"; +import { EllipticPoint, KeyType } from "@tkey/common-types"; import { UX_MODE_TYPE } from "@toruslabs/customauth"; import { keccak256 } from "@toruslabs/metadata-helpers"; import { tssLib } from "@toruslabs/tss-dkls-lib"; @@ -33,24 +33,29 @@ const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit) => { assert.strictEqual(coreKitInstance.status, COREKIT_STATUS.LOGGED_IN); assert.strictEqual(keyDetails.requiredFactors, 0); const factorkey = coreKitInstance.getCurrentFactorKey(); - await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); + const keyType = coreKitInstance.getSupportedCurveKeyTypes()[0]; + await coreKitInstance.getTssShare({keyType, factorkey: new BN(factorkey.factorKey, "hex")}); }; variable.forEach((testVariable) => { const { web3AuthNetwork, uxMode, manualSync, email } = testVariable; + const keyType = tssLib.keyType as KeyType; const storageInstance = new MemoryStorage(); - const newCoreKitInstance = () => - new Web3AuthMPCCoreKit({ + const newCoreKitInstance = () => { + const instance = new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLibs: [tssLib], + supportedKeyTypes: [keyType], storage: storageInstance, manualSync, legacyFlag: true, }); + instance.addTssLibs([tssLib]) + return instance; + } const coreKitInstance = newCoreKitInstance(); @@ -75,14 +80,11 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - const tssPublicPoint = bufferToElliptic(coreKitInstance.getPubKey()); - const { metadataPubKey, tssPubKey } = coreKitInstance.getKeyDetails(); + const tssPublicPoint = bufferToElliptic(coreKitInstance.getPubKey(keyType)); + const { metadataPubKey } = coreKitInstance.getKeyDetails(); assert.strictEqual(tssPublicPoint.getX().toString("hex"), "d2869f27c3e226d90b275b008f7dc67b8f4b208900a7b98ecc4e5266807d382c"); assert.strictEqual(tssPublicPoint.getY().toString("hex"), "15860fd569413eb7f177e655c4bf855f37920b800235de344fdd518196becfe0"); - assert.strictEqual(tssPubKey.x.toString("hex"), "d2869f27c3e226d90b275b008f7dc67b8f4b208900a7b98ecc4e5266807d382c"); - assert.strictEqual(tssPubKey.y.toString("hex"), "15860fd569413eb7f177e655c4bf855f37920b800235de344fdd518196becfe0"); - assert.strictEqual(metadataPubKey.x.toString("hex"), "b3951a441f87ecea4672edc82894ac023316723cf164a93adec72b58a27a1f06"); assert.strictEqual(metadataPubKey.y.toString("hex"), "3be6c118d94242a650e8aebbefcd37ebeceeb927d0ed51f3d2ba723b8fd2740b"); }); @@ -122,11 +124,11 @@ variable.forEach((testVariable) => { const msg = "hello world"; const msgBuffer = Buffer.from(msg); const msgHash = keccak256(msgBuffer); - const signature = sigToRSV(await coreKitInstance.sign(msgHash, { hashed: true } )); + const signature = sigToRSV(await coreKitInstance.signECDSA(msgHash, { hashed: true } )); const secp256k1 = new EC("secp256k1"); const pubkey = secp256k1.recoverPubKey(msgHash, signature, signature.v) as EllipticPoint; - const publicKeyPoint = bufferToElliptic(coreKitInstance.getPubKey()); + const publicKeyPoint = bufferToElliptic(coreKitInstance.getPubKey(keyType)); assert(pubkey.eq(publicKeyPoint)); }); }); diff --git a/tests/bip340.spec.ts b/tests/bip340.spec.ts index db8bb961..1c97e723 100644 --- a/tests/bip340.spec.ts +++ b/tests/bip340.spec.ts @@ -1,14 +1,14 @@ import assert from "node:assert"; import test from "node:test"; -import { EllipticPoint } from "@tkey/common-types"; +import { EllipticPoint, KeyType } from "@tkey/common-types"; import { UX_MODE_TYPE } from "@toruslabs/customauth"; import { tssLib } from "@toruslabs/tss-frost-lib-bip340"; import BN from "bn.js"; import { schnorr as bip340 } from '@noble/curves/secp256k1'; import { AsyncStorage, COREKIT_STATUS, MemoryStorage, WEB3AUTH_NETWORK, WEB3AUTH_NETWORK_TYPE, Web3AuthMPCCoreKit } from "../src"; -import { bufferToElliptic, criticalResetAccount, mockLogin, mockLogin2 } from "./setup"; +import { criticalResetAccount, mockLogin, mockLogin2 } from "./setup"; import { getKeyCurve } from "@toruslabs/torus.js"; type TestVariable = { @@ -32,23 +32,31 @@ const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit, accountIndex = 0) assert.strictEqual(coreKitInstance.status, COREKIT_STATUS.LOGGED_IN); assert.strictEqual(keyDetails.requiredFactors, 0); const factorkey = coreKitInstance.getCurrentFactorKey(); - await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex"), accountIndex ); + const keyType = coreKitInstance.getSupportedCurveKeyTypes()[0] + await coreKitInstance.getTssShare({ keyType, factorkey: new BN(factorkey.factorKey, "hex"), accountIndex }); }; const storageInstance = new MemoryStorage(); variable.forEach((testVariable) => { const { web3AuthNetwork, uxMode, manualSync, email } = testVariable; - const newCoreKitInstance = () => - new Web3AuthMPCCoreKit({ - web3AuthClientId: "torus-key-test", - web3AuthNetwork, - baseUrl: "http://localhost:3000", - uxMode, - tssLibs : [tssLib], - storage: storageInstance, - manualSync, - }); + + const keyType = tssLib.keyType as KeyType; + + const newCoreKitInstance = () => { + const instance = + new Web3AuthMPCCoreKit({ + web3AuthClientId: "torus-key-test", + web3AuthNetwork, + baseUrl: "http://localhost:3000", + uxMode, + supportedKeyTypes: [keyType], + storage: storageInstance, + manualSync, + }); + instance.addTssLibs([tssLib]) + return instance; + }; async function resetAccount() { const resetInstance = newCoreKitInstance(); @@ -84,10 +92,10 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - const tssCurve = getKeyCurve(coreKitInstance.keyType) - checkPubKey = coreKitInstance.getPubKeyPoint().toEllipticPoint(tssCurve); + const tssCurve = getKeyCurve(keyType) + checkPubKey = coreKitInstance.getPubKeyPoint(keyType).toEllipticPoint(tssCurve); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); + const { tssShare } = await coreKitInstance.getTssShare( { keyType, factorkey: new BN(factorkey.factorKey, "hex")}); checkTssShare = tssShare; if (manualSync) { @@ -123,10 +131,10 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - const tssCurve = getKeyCurve(coreKitInstance.keyType) - const newPubKey = coreKitInstance.getPubKeyPoint().toEllipticPoint(tssCurve); + const tssCurve = getKeyCurve(keyType) + const newPubKey = coreKitInstance.getPubKeyPoint(keyType).toEllipticPoint(tssCurve); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare: newTssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); + const { tssShare: newTssShare } = await coreKitInstance.getTssShare({ keyType, factorkey: new BN(factorkey.factorKey, "hex") }); assert(checkPubKey.eq(newPubKey)); assert(checkTssShare.eq(newTssShare)); }); @@ -143,7 +151,7 @@ variable.forEach((testVariable) => { const msg = "hello world"; const msgBuffer = Buffer.from(msg); - const signature = await coreKitInstance.sign(msgBuffer); + const signature = await coreKitInstance.signBip340(msgBuffer); const pk = coreKitInstance.getPubKeyBip340(); const valid = bip340.verify(signature, msgBuffer, pk); assert(valid); diff --git a/tests/ed25519.spec.ts b/tests/ed25519.spec.ts index 11e9fbfc..599d6ef5 100644 --- a/tests/ed25519.spec.ts +++ b/tests/ed25519.spec.ts @@ -1,7 +1,7 @@ import assert from "node:assert"; import test from "node:test"; -import { EllipticPoint } from "@tkey/common-types"; +import { EllipticPoint, KeyType } from "@tkey/common-types"; import { UX_MODE_TYPE } from "@toruslabs/customauth"; import { tssLib } from "@toruslabs/tss-frost-lib"; import BN from "bn.js"; @@ -31,20 +31,22 @@ const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit, accountIndex = 0) assert.strictEqual(coreKitInstance.status, COREKIT_STATUS.LOGGED_IN); assert.strictEqual(keyDetails.requiredFactors, 0); const factorkey = coreKitInstance.getCurrentFactorKey(); - await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex") ,accountIndex); + const keyType = coreKitInstance.getSupportedCurveKeyTypes()[0]; + await coreKitInstance.getTssShare({ keyType, factorkey: new BN(factorkey.factorKey, "hex"), accountIndex }); }; const storageInstance = new MemoryStorage(); variable.forEach((testVariable) => { const { web3AuthNetwork, uxMode, manualSync, email } = testVariable; + const keyType = tssLib.keyType as KeyType; const newCoreKitInstance = () => new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLibs: [tssLib], + supportedKeyTypes: [keyType], storage: storageInstance, manualSync, legacyFlag: true, @@ -84,10 +86,10 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - const tssCurve = getKeyCurve(coreKitInstance.keyType) - checkPubKey = bufferToElliptic(coreKitInstance.getPubKey(), tssCurve); + const tssCurve = getKeyCurve(keyType) + checkPubKey = bufferToElliptic(coreKitInstance.getPubKey(keyType), tssCurve); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); + const { tssShare } = await coreKitInstance.getTssShare({keyType, factorkey: new BN(factorkey.factorKey, "hex")}); checkTssShare = tssShare; if (manualSync) { @@ -123,16 +125,19 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - const tssCurve = getKeyCurve(coreKitInstance.keyType) - const newPubKey = bufferToElliptic(coreKitInstance.getPubKey(), tssCurve); + const tssCurve = getKeyCurve(keyType) + const newPubKey = bufferToElliptic(coreKitInstance.getPubKey(keyType), tssCurve); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare: newTssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); + const { tssShare: newTssShare } = await coreKitInstance.getTssShare({ keyType, factorkey: new BN(factorkey.factorKey, "hex") }); assert(checkPubKey.eq(newPubKey)); assert(checkTssShare.eq(newTssShare)); }); await t.test("#able to sign", async function () { const coreKitInstance = newCoreKitInstance(); + // add signing lib + coreKitInstance.addTssLibs([tssLib]); + await coreKitInstance.init({ handleRedirectResult: false, rehydrate: false }); const localToken = await mockLogin2(email); await coreKitInstance.loginWithJWT({ @@ -143,7 +148,7 @@ variable.forEach((testVariable) => { const msg = "hello world"; const msgBuffer = Buffer.from(msg); - const signature = ed25519().makeSignature((await coreKitInstance.sign(msgBuffer)).toString("hex")); + const signature = ed25519().makeSignature((await coreKitInstance.signEd25519(msgBuffer)).toString("hex")); const valid = ed25519().verify(msgBuffer, signature, coreKitInstance.getPubKeyEd25519()); assert(valid); }); diff --git a/tests/factors.spec.ts b/tests/factors.spec.ts index 6973fa4b..4c0ffe25 100644 --- a/tests/factors.spec.ts +++ b/tests/factors.spec.ts @@ -1,7 +1,7 @@ import assert from "node:assert"; import test from "node:test"; -import { EllipticPoint, Point } from "@tkey/common-types"; +import { EllipticPoint, KeyType, Point } from "@tkey/common-types"; import { factorKeyCurve } from "@tkey/tss"; import { tssLib as tssLibDKLS } from "@toruslabs/tss-dkls-lib"; import { tssLib as tssLibFROST } from "@toruslabs/tss-frost-lib"; @@ -22,26 +22,28 @@ type FactorTestVariable = { }; function getPubKeys(kit: Web3AuthMPCCoreKit, indices: number[]): EllipticPoint[] { - if (!kit.supportsAccountIndex) { + const keyType = kit.getSupportedCurveKeyTypes()[0]; + if (keyType !== KeyType.ed25519) { indices = indices.filter((i) => i === 0); } - const tssCurve = getKeyCurve(kit.keyType) + const tssCurve = getKeyCurve(keyType) const pubKeys = indices.map((i) => { - return kit.getPubKeyPoint( i).toEllipticPoint(tssCurve); + return kit.getPubKeyPoint(keyType, i).toEllipticPoint(tssCurve); }); return pubKeys; } export const FactorManipulationTest = async (testVariable: FactorTestVariable) => { const { email, tssLib } = testVariable; - const tsslibs = tssLib ? [tssLib] : [tssLibDKLS]; + const localTssLib = tssLib ?? tssLibDKLS; + const keyType = localTssLib.keyType as KeyType; const newInstance = async () => { const instance = new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, baseUrl: "http://localhost:3000", uxMode: "nodejs", - tssLibs: tsslibs, + supportedKeyTypes: [keyType], storage: testVariable.storage, manualSync: testVariable.manualSync, }); @@ -74,7 +76,7 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = const coreKitInstance = await newInstance(); assert.equal(coreKitInstance.status, COREKIT_STATUS.LOGGED_IN); - if (coreKitInstance.supportsAccountIndex) { + if (keyType !== KeyType.ed25519) { coreKitInstance.setTssWalletIndex(1); } const tssPubKeys = getPubKeys(coreKitInstance, [0, 1, 99]); @@ -91,7 +93,7 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = shareType: TssShareType.DEVICE, }); - if (coreKitInstance.supportsAccountIndex) { + if (keyType!== KeyType.ed25519) { coreKitInstance.setTssWalletIndex(2); } const factorKey2 = await coreKitInstance.createFactor({ @@ -115,14 +117,14 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = // try inputFactor ( set as active factor ) // delete factor - if (coreKitInstance.supportsAccountIndex) { + if (keyType!== KeyType.ed25519) { instance2.setTssWalletIndex(0); } const pt = Point.fromScalar(new BN(factorKey1, "hex"), factorKeyCurve); await instance2.deleteFactor(pt); // delete factor - if (coreKitInstance.supportsAccountIndex) { + if (keyType!== KeyType.ed25519) { instance2.setTssWalletIndex(1); } const pt2 = Point.fromScalar(new BN(factorKey2, "hex"), factorKeyCurve); @@ -150,7 +152,7 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = const instance = await newInstance(); assert.strictEqual(instance.status, COREKIT_STATUS.LOGGED_IN); - if (instance.supportsAccountIndex) { + if (keyType!== KeyType.ed25519) { instance.setTssWalletIndex(1); } const recoverFactor = await instance.enableMFA({}); diff --git a/tests/gating.spec.ts b/tests/gating.spec.ts index 4b786eca..a9a34916 100644 --- a/tests/gating.spec.ts +++ b/tests/gating.spec.ts @@ -6,6 +6,7 @@ import assert from "assert"; import { COREKIT_STATUS, MemoryStorage, WEB3AUTH_NETWORK, WEB3AUTH_NETWORK_TYPE, Web3AuthMPCCoreKit } from "../src"; import { criticalResetAccount, mockLogin } from "./setup"; +import { KeyType } from "@tkey/common-types"; type TestVariable = { description: string; @@ -47,12 +48,13 @@ const variable: TestVariable[] = [ variable.forEach((testVariable) => { const { web3AuthNetwork, uxMode, manualSync, email, web3ClientID: web3AuthClientId, expectedErrorThrown } = testVariable; + const keyType = tssLib.keyType as KeyType; const coreKitInstance = new Web3AuthMPCCoreKit({ web3AuthClientId, web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLibs: [tssLib], + supportedKeyTypes: [keyType], storage: new MemoryStorage(), manualSync, }); diff --git a/tests/importRecovery.spec.ts b/tests/importRecovery.spec.ts index 6964a4f9..7efd8fc1 100644 --- a/tests/importRecovery.spec.ts +++ b/tests/importRecovery.spec.ts @@ -1,5 +1,5 @@ import assert from "node:assert"; -import test from "node:test"; +import test, { describe, it } from "node:test"; import { tssLib as tssLibDKLS } from "@toruslabs/tss-dkls-lib"; import { tssLib as tssLibFROST } from "@toruslabs/tss-frost-lib"; @@ -7,15 +7,22 @@ import { tssLib as tssLibFROST } from "@toruslabs/tss-frost-lib"; import { AsyncStorage, MemoryStorage, TssLibType, TssShareType, WEB3AUTH_NETWORK } from "../src"; import { bufferToElliptic, criticalResetAccount, newCoreKitLogInInstance } from "./setup"; import { getKeyCurve } from "@toruslabs/torus.js"; +import { KeyType, Point } from "@tkey/common-types"; +import { MockStorageLayer } from "@tkey/storage-layer-torus"; +import { BN } from "bn.js"; type ImportKeyTestVariable = { manualSync?: boolean; email: string; importKeyEmail: string; tssLib: TssLibType; + legacyFlag?: boolean; }; const storageInstance = new MemoryStorage(); + +// use mockStorageLayer, hence resetAccount is not required. +const mockStorageLayer = new MockStorageLayer(); export const ImportTest = async (testVariable: ImportKeyTestVariable) => { async function newCoreKitInstance(email: string, importTssKey?: string) { return newCoreKitLogInInstance({ @@ -25,27 +32,16 @@ export const ImportTest = async (testVariable: ImportKeyTestVariable) => { storageInstance, tssLib: testVariable.tssLib, importTssKey, + legacyFlag: testVariable.legacyFlag, + mockStorageLayer, }); } - async function resetAccount(email: string) { - const kit = await newCoreKitInstance(email); - await criticalResetAccount(kit); - await kit.logout(); - await new AsyncStorage(kit._storageKey, storageInstance).resetStore(); - } - - test(`import recover tss key : ${testVariable.manualSync}`, async function (t) { - const beforeTest = async () => { - await resetAccount(testVariable.email); - await resetAccount(testVariable.importKeyEmail); - }; - - await beforeTest(); - - await t.test("#recover Tss key using 2 factors key, import tss key to new oauth login", async function () { + describe(`import recover tss key : ${testVariable.manualSync}, testVariable: ${testVariable}`, async function (t) { + it("#recover Tss key using 2 factors key, import tss key to new oauth login", async function () { const coreKitInstance = await newCoreKitInstance(testVariable.email); + const keyType = coreKitInstance.getSupportedCurveKeyTypes()[0]; // Create 2 factors which will be used to recover tss key. const factorKeyDevice = await coreKitInstance.createFactor({ shareType: TssShareType.DEVICE, @@ -60,54 +56,57 @@ export const ImportTest = async (testVariable: ImportKeyTestVariable) => { } // Export key and logout. - const exportedTssKey1 = await coreKitInstance._UNSAFE_exportTssKey(); + const exportedTssKey1 = await coreKitInstance._UNSAFE_exportTssKey(keyType); + + const ed25519ImportSeed = (keyType === KeyType.ed25519)? (await coreKitInstance._UNSAFE_exportTssEd25519Seed()).toString("hex") : undefined ; await coreKitInstance.logout(); + // logout re-init storagelayer, reassign to mock is required + coreKitInstance.tKey.storageLayer = mockStorageLayer; + // Recover key from any two factors. - const recoveredTssKey = await coreKitInstance._UNSAFE_recoverTssKey([factorKeyDevice, factorKeyRecovery]); + const recoveredTssKey = await coreKitInstance._UNSAFE_recoverTssKey([factorKeyDevice, factorKeyRecovery], keyType); assert.strictEqual(recoveredTssKey, exportedTssKey1); + // import for ed25519 need to be seed. + const importKey = ed25519ImportSeed ?? recoveredTssKey ; + // Initialize new instance and import existing key. - const coreKitInstance2 = await newCoreKitInstance(testVariable.importKeyEmail, recoveredTssKey); + const coreKitInstance2 = await newCoreKitInstance(testVariable.importKeyEmail, importKey); if (testVariable.manualSync) { await coreKitInstance2.commitChanges(); } // Export key. - const exportedTssKey = await coreKitInstance2._UNSAFE_exportTssKey(); + const exportedTssKey = await coreKitInstance2._UNSAFE_exportTssKey(keyType); assert.strictEqual(exportedTssKey, recoveredTssKey); // Check exported key corresponds to pub key. const coreKitInstance3 = await newCoreKitInstance(testVariable.importKeyEmail); - const tssPubkey = bufferToElliptic(coreKitInstance3.getPubKey()); + const tssPubkey = coreKitInstance3.getPubKeyPoint(keyType).toEllipticPoint(getKeyCurve(keyType)); - const exportedTssKey3 = await coreKitInstance3._UNSAFE_exportTssKey(); - const tssCurve = getKeyCurve(coreKitInstance.keyType); + const exportedTssKey3 = await coreKitInstance3._UNSAFE_exportTssKey(keyType); + const tssCurve = getKeyCurve(keyType); const exportedPub = tssCurve.keyFromPrivate(exportedTssKey3).getPublic(); + console.log(exportedPub.encodeCompressed("hex")) + console.log(tssPubkey.encodeCompressed("hex")) assert(tssPubkey.eq(exportedPub)); // Check exported key corresponds to pub key for account index > 0. - if (coreKitInstance3.supportsAccountIndex) { + if (keyType !== KeyType.ed25519) { coreKitInstance3.setTssWalletIndex(1); - const exportedTssKeyIndex1 = await coreKitInstance3._UNSAFE_exportTssKey(); + const exportedTssKeyIndex1 = await coreKitInstance3._UNSAFE_exportTssKey(keyType); const exportedPubIndex1 = tssCurve.keyFromPrivate(exportedTssKeyIndex1).getPublic(); - const tssPubKeyIndex1 = bufferToElliptic(coreKitInstance3.getPubKey()); + const tssPubKeyIndex1 = bufferToElliptic(coreKitInstance3.getPubKey(keyType)); assert(exportedPubIndex1.eq(tssPubKeyIndex1)); } }); - - t.afterEach(function () { - return console.info("finished running recovery test"); - }); - t.after(function () { - return console.info("finished running recovery tests"); - }); }); }; const variable: ImportKeyTestVariable[] = [ - { manualSync: false, email: "emailexport", importKeyEmail: "emailimport", tssLib: tssLibDKLS }, - { manualSync: true, email: "emailexport", importKeyEmail: "emailimport", tssLib: tssLibDKLS }, + // { manualSync: false, email: "emailexport", importKeyEmail: "emailimport", tssLib: tssLibDKLS }, + // { manualSync: true, email: "emailexport", importKeyEmail: "emailimport", tssLib: tssLibDKLS }, { manualSync: false, email: "emailexport_ed25519", importKeyEmail: "emailimport_ed25519", tssLib: tssLibFROST }, ]; diff --git a/tests/login.spec.ts b/tests/login.spec.ts index 57a311d8..7489fbb7 100644 --- a/tests/login.spec.ts +++ b/tests/login.spec.ts @@ -1,7 +1,7 @@ import assert from "node:assert"; import test from "node:test"; -import { EllipticPoint } from "@tkey/common-types"; +import { EllipticPoint, KeyType } from "@tkey/common-types"; import { UX_MODE_TYPE } from "@toruslabs/customauth"; import { keccak256 } from "@toruslabs/metadata-helpers"; import { tssLib } from "@toruslabs/tss-dkls-lib"; @@ -33,20 +33,22 @@ const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit, accountIndex = 0) assert.strictEqual(coreKitInstance.status, COREKIT_STATUS.LOGGED_IN); assert.strictEqual(keyDetails.requiredFactors, 0); const factorkey = coreKitInstance.getCurrentFactorKey(); - await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex"), accountIndex ); + const keyType = coreKitInstance.getSupportedCurveKeyTypes()[0]; + await coreKitInstance.getTssShare({ keyType, factorkey: new BN(factorkey.factorKey, "hex"), accountIndex }); }; const storageInstance = new MemoryStorage(); variable.forEach((testVariable) => { const { web3AuthNetwork, uxMode, manualSync, email } = testVariable; + const keyType = tssLib.keyType as KeyType; const newCoreKitInstance = () => new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLibs: [tssLib], + supportedKeyTypes: [keyType], storage: storageInstance, manualSync, }); @@ -63,7 +65,7 @@ variable.forEach((testVariable) => { web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLibs: [tssLib], + supportedKeyTypes: [keyType], storage: storageInstance, manualSync, }); @@ -93,9 +95,9 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - checkPubKey = bufferToElliptic(coreKitInstance.getPubKey()); + checkPubKey = bufferToElliptic(coreKitInstance.getPubKey(keyType)); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); + const { tssShare } = await coreKitInstance.getTssShare({ keyType, factorkey: new BN(factorkey.factorKey, "hex") }); checkTssShare = tssShare; if (manualSync) { @@ -131,15 +133,16 @@ variable.forEach((testVariable) => { // get key details await checkLogin(coreKitInstance); - const newPubKey = bufferToElliptic(coreKitInstance.getPubKey()); + const newPubKey = bufferToElliptic(coreKitInstance.getPubKey(keyType)); const factorkey = coreKitInstance.getCurrentFactorKey(); - const { tssShare: newTssShare } = await coreKitInstance.getTssShare(new BN(factorkey.factorKey, "hex")); + const { tssShare: newTssShare } = await coreKitInstance.getTssShare({ keyType, factorkey: new BN(factorkey.factorKey, "hex") }); assert(checkPubKey.eq(newPubKey)); assert(checkTssShare.eq(newTssShare)); }); await t.test("#able to sign", async function () { const coreKitInstance = newCoreKitInstance(); + coreKitInstance.addTssLibs([tssLib]) await coreKitInstance.init({ handleRedirectResult: false, rehydrate: false }); const localToken = await mockLogin2(email); await coreKitInstance.loginWithJWT({ @@ -153,13 +156,13 @@ variable.forEach((testVariable) => { const secp256k1 = new EC("secp256k1"); // Sign hash. - const signature = sigToRSV(await coreKitInstance.sign(msgHash, { hashed: true })); + const signature = sigToRSV(await coreKitInstance.signECDSA(msgHash, { hashed: true })); const pubkey = secp256k1.recoverPubKey(msgHash, signature, signature.v) as EllipticPoint; - const publicKeyPoint = bufferToElliptic(coreKitInstance.getPubKey()); + const publicKeyPoint = bufferToElliptic(coreKitInstance.getPubKey(keyType)); assert(pubkey.eq(publicKeyPoint)); // Sign full message. - const signature2 = sigToRSV(await coreKitInstance.sign(msgBuffer)); + const signature2 = sigToRSV(await coreKitInstance.signECDSA(msgBuffer)); const pubkey2 = secp256k1.recoverPubKey(msgHash, signature2, signature2.v) as EllipticPoint; assert(pubkey2.eq(publicKeyPoint)); }); @@ -179,13 +182,14 @@ variable.forEach((testVariable) => { const secp256k1 = new EC("secp256k1"); await coreKitInstance.setTssWalletIndex(0); + coreKitInstance.addTssLibs([tssLib]) const msg = "hello world 1"; const msgBuffer = Buffer.from(msg); const msgHash = keccak256(msgBuffer); - const signature1 = sigToRSV(await coreKitInstance.sign(msgHash, { hashed: true })); + const signature1 = sigToRSV(await coreKitInstance.signECDSA(msgHash, { hashed: true })); const pubkeyIndex0 = secp256k1.recoverPubKey(msgHash, signature1, signature1.v); - const publicKeyPoint0 = bufferToElliptic(coreKitInstance.getPubKey()); + const publicKeyPoint0 = bufferToElliptic(coreKitInstance.getPubKey(keyType)); assert(pubkeyIndex0.eq(publicKeyPoint0)); await coreKitInstance.setTssWalletIndex(1); @@ -194,10 +198,10 @@ variable.forEach((testVariable) => { const msgBuffer1 = Buffer.from(msg1); const msgHash1 = keccak256(msgBuffer1); - const signature2 = sigToRSV(await coreKitInstance.sign(msgHash1, { hashed: true })); + const signature2 = sigToRSV(await coreKitInstance.signECDSA(msgHash1, { hashed: true })); const pubkeyIndex1 = secp256k1.recoverPubKey(msgHash1, signature2, signature2.v) as EllipticPoint; - const publicKeyPoint1 = bufferToElliptic(coreKitInstance.getPubKey()); + const publicKeyPoint1 = bufferToElliptic(coreKitInstance.getPubKey(keyType)); assert(pubkeyIndex1.eq(publicKeyPoint1)); await checkLogin(coreKitInstance, 1); @@ -207,10 +211,10 @@ variable.forEach((testVariable) => { const msg2 = "hello world 3"; const msgBuffer2 = Buffer.from(msg2); const msgHash2 = keccak256(msgBuffer2); - const signature3 = sigToRSV(await coreKitInstance.sign(msgHash2, { hashed: true })); + const signature3 = sigToRSV(await coreKitInstance.signECDSA(msgHash2, { hashed: true })); const pubkeyIndex2 = secp256k1.recoverPubKey(msgHash2, signature3, signature3.v) as EllipticPoint; - const publicKeyPoint2 = bufferToElliptic(coreKitInstance.getPubKey()); + const publicKeyPoint2 = bufferToElliptic(coreKitInstance.getPubKey(keyType)); assert(pubkeyIndex2.eq(publicKeyPoint2)); await checkLogin(coreKitInstance, 2); @@ -233,11 +237,11 @@ variable.forEach((testVariable) => { }); coreKitInstance.setTssWalletIndex(0); - const pubkey3index0 = bufferToElliptic(coreKitInstance3.getPubKey()); + const pubkey3index0 = bufferToElliptic(coreKitInstance3.getPubKey(keyType)); coreKitInstance3.setTssWalletIndex(1); - const pubkey3index1 = bufferToElliptic(coreKitInstance3.getPubKey()); + const pubkey3index1 = bufferToElliptic(coreKitInstance3.getPubKey(keyType)); coreKitInstance3.setTssWalletIndex(2); - const pubkey3index2 = bufferToElliptic(coreKitInstance3.getPubKey()); + const pubkey3index2 = bufferToElliptic(coreKitInstance3.getPubKey(keyType)); assert(pubkeyIndex0.eq(pubkey3index0)); assert(pubkeyIndex1.eq(pubkey3index1)); diff --git a/tests/multiCurveTest.ts b/tests/multiCurveTest.ts index a1cb5a98..e73a95ee 100644 --- a/tests/multiCurveTest.ts +++ b/tests/multiCurveTest.ts @@ -93,7 +93,6 @@ describe("multiCurveTest", () => { const recoverFactor = await instance.enableMFA({}) - console.log(recoverFactor); await testAllSigning(instance); diff --git a/tests/securityQuestion.spec.ts b/tests/securityQuestion.spec.ts index ae24366a..a926f917 100644 --- a/tests/securityQuestion.spec.ts +++ b/tests/securityQuestion.spec.ts @@ -16,6 +16,7 @@ import { Web3AuthMPCCoreKit, } from "../src"; import { criticalResetAccount, mockLogin } from "./setup"; +import { KeyType } from "@tkey/common-types"; type TestVariable = { web3AuthNetwork: WEB3AUTH_NETWORK_TYPE; @@ -26,6 +27,8 @@ type TestVariable = { const storageInstance = new MemoryStorage(); export const TssSecurityQuestionsTest = async (newInstance: () => Promise, testVariable: TestVariable) => { + + const keyType = tssLib.keyType as KeyType; test(`#Tss Security Question - ${testVariable.manualSync} `, async function (t) { async function beforeTest() { const coreKitInstance = await newInstance(); @@ -63,7 +66,7 @@ export const TssSecurityQuestionsTest = async (newInstance: () => Promise securityQuestion.recoverFactor(instance, "wrong answer")); @@ -77,26 +80,26 @@ export const TssSecurityQuestionsTest = async (newInstance: () => Promise instance.getTssShare(new BN(factor, "hex"))); + await assert.rejects(() => instance.getTssShare({ keyType, factorkey: new BN(factor, "hex") })); // recover factor // check wrong answer @@ -126,13 +129,14 @@ const variable: TestVariable[] = [ const email = "testmail99"; variable.forEach(async (testVariable) => { + const keyType = tssLib.keyType as KeyType; const newCoreKitLogInInstance = async () => { const instance = new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, baseUrl: "http://localhost:3000", uxMode: "nodejs", - tssLibs: [tssLib], + supportedKeyTypes: [keyType], storage: storageInstance, manualSync: testVariable.manualSync, }); diff --git a/tests/sessionTime.spec.ts b/tests/sessionTime.spec.ts index 0fae1a58..a68fa57c 100644 --- a/tests/sessionTime.spec.ts +++ b/tests/sessionTime.spec.ts @@ -6,6 +6,7 @@ import { tssLib } from "@toruslabs/tss-dkls-lib"; import { COREKIT_STATUS, MemoryStorage, WEB3AUTH_NETWORK, WEB3AUTH_NETWORK_TYPE, Web3AuthMPCCoreKit } from "../src"; import { criticalResetAccount, mockLogin } from "./setup"; +import { KeyType } from "@tkey/common-types"; type TestVariable = { web3AuthNetwork: WEB3AUTH_NETWORK_TYPE; @@ -70,7 +71,7 @@ variable.forEach(async (testVariable) => { web3AuthNetwork, baseUrl: "http://localhost:3000", uxMode, - tssLibs : [tssLib], + supportedKeyTypes: [tssLib.keyType as KeyType], storage: new MemoryStorage(), manualSync, sessionTime, @@ -97,7 +98,6 @@ variable.forEach(async (testVariable) => { } }); - console.log(coreKitInstance.keyType) await coreKitInstance.loginWithJWT({ verifier: "torus-test-health", verifierId: parsedToken.email, diff --git a/tests/setup.ts b/tests/setup.ts index 9a05553c..86a9c1bc 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -1,11 +1,11 @@ -import { EllipticPoint, secp256k1 } from "@tkey/common-types"; -import { tssLib } from "@toruslabs/tss-dkls-lib"; +import { EllipticPoint, KeyType, secp256k1 } from "@tkey/common-types"; import BN from "bn.js"; import jwt, { Algorithm } from "jsonwebtoken"; import { tssLib as tssLibDKLS } from "@toruslabs/tss-dkls-lib"; import { TorusKey } from "@toruslabs/torus.js"; import { IAsyncStorage, IStorage, parseToken, TssLibType, WEB3AUTH_NETWORK_TYPE, Web3AuthMPCCoreKit } from "../src"; +import { MockStorageLayer } from "@tkey/storage-layer-torus"; export const mockLogin2 = async (email: string) => { const req = new Request("https://li6lnimoyrwgn2iuqtgdwlrwvq0upwtr.lambda-url.eu-west-1.on.aws/", { @@ -90,6 +90,9 @@ export const newCoreKitLogInInstance = async ({ importTssKey, registerExistingSFAKey, login, + mockStorageLayer, + tssLib, + legacyFlag, }: { network: WEB3AUTH_NETWORK_TYPE; manualSync: boolean; @@ -99,25 +102,39 @@ export const newCoreKitLogInInstance = async ({ importTssKey?: string; registerExistingSFAKey?: boolean; login?: LoginFunc; + mockStorageLayer?: MockStorageLayer; + legacyFlag?: boolean; }) => { - const tssLibs = [tssLib || tssLibDKLS]; + const localTsslib = tssLib ?? tssLibDKLS; + // console.log("localTssLib", localTsslib) + + const instance = new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", web3AuthNetwork: network, baseUrl: "http://localhost:3000", uxMode: "nodejs", - tssLibs: tssLibs, + supportedKeyTypes: [localTsslib.keyType as KeyType], storage: storageInstance, manualSync, + legacyFlag, }); + instance.addTssLibs([localTsslib]) const { idToken, parsedToken } = login ? await login(email) : await mockLogin(email); await instance.init(); + + // console.log("legacy Flag", legacyFlag) + if (mockStorageLayer) { + instance.tKey.storageLayer = mockStorageLayer + } + + const finalImportKey = importTssKey ? { [localTsslib.keyType]: importTssKey } : undefined; await instance.loginWithJWT({ verifier: "torus-test-health", verifierId: parsedToken.email, idToken, - importTssKey: importTssKey ? { [tssLibs[0].keyType] : importTssKey} : undefined, + importTssKey: finalImportKey, registerExistingSFAKey }); @@ -130,6 +147,9 @@ export const loginWithSFA = async ({ email, storageInstance, login, + tssLib, + legacyFlag, + mockStorageLayer, }: { network: WEB3AUTH_NETWORK_TYPE; manualSync: boolean; @@ -137,22 +157,31 @@ export const loginWithSFA = async ({ storageInstance: IStorage | IAsyncStorage; tssLib?: TssLibType; login?: LoginFunc; + legacyFlag?: boolean; + mockStorageLayer?: MockStorageLayer; }): Promise => { - const tssLibs = [tssLib || tssLibDKLS] + const localTssLib = tssLib ?? tssLibDKLS const instance = new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", web3AuthNetwork: network, baseUrl: "http://localhost:3000", uxMode: "nodejs", - tssLibs: tssLibs, + supportedKeyTypes: [localTssLib.keyType as KeyType], storage: storageInstance, manualSync, + legacyFlag, }); const { idToken, parsedToken } = login ? await login(email) : await mockLogin(email); await instance.init(); + + // mock storate layer + if (mockStorageLayer) { + instance.tKey.storageLayer = mockStorageLayer + } + const nodeDetails = await instance.torusSp.customAuthInstance.nodeDetailManager.getNodeDetails({ verifier: "torus-test-health", verifierId: parsedToken.email, @@ -188,7 +217,7 @@ export function bufferToElliptic(p: Buffer, ec = secp256k1): EllipticPoint { export function generateRandomEmail(): string { - const username = stringGen(10); + const username = stringGen(100); const domain = stringGen(5); const tld = stringGen(3); return `${username}@${domain}.${tld}`; diff --git a/tests/sfaImport.spec.ts b/tests/sfaImport.spec.ts index bfd2ec97..d37ec978 100644 --- a/tests/sfaImport.spec.ts +++ b/tests/sfaImport.spec.ts @@ -1,31 +1,35 @@ import assert from "node:assert"; -import test from "node:test"; +import test, { after, before, describe, it } from "node:test"; import { tssLib as tssLibDKLS } from "@toruslabs/tss-dkls-lib"; import { tssLib as tssLibFROST } from "@toruslabs/tss-frost-lib"; import { AsyncStorage, MemoryStorage, TssLibType, TssShareType, WEB3AUTH_NETWORK } from "../src"; import { criticalResetAccount, generateRandomEmail, loginWithSFA, newCoreKitLogInInstance } from "./setup"; +import { KeyType } from "@tkey/common-types"; type ImportKeyTestVariable = { manualSync?: boolean; email: string; tssLib: TssLibType; + legacyFlag: boolean; }; const storageInstance = new MemoryStorage(); export const ImportSFATest = async (testVariable: ImportKeyTestVariable) => { async function newCoreKitInstance(email: string) { - return newCoreKitLogInInstance({ + const instance = await newCoreKitLogInInstance({ network: WEB3AUTH_NETWORK.DEVNET, manualSync: testVariable.manualSync, email: email, storageInstance, tssLib: testVariable.tssLib, registerExistingSFAKey: true, + legacyFlag: testVariable.legacyFlag, }); + return instance; } - + async function resetAccount(email: string) { const kit = await newCoreKitInstance(email); await criticalResetAccount(kit); @@ -33,17 +37,24 @@ export const ImportSFATest = async (testVariable: ImportKeyTestVariable) => { await new AsyncStorage(kit._storageKey, storageInstance).resetStore(); } - test(`import sfa key and recover tss key : ${testVariable.manualSync}`, async function (t) { - const afterTest = async () => { - await resetAccount(testVariable.email); - }; - await t.test("#recover Tss key using 2 factors key, import tss key to new oauth login", async function () { + describe(`import sfa key and recover tss key manualSync: ${testVariable.manualSync} siging lib ${testVariable.tssLib.sigType}`, async function (t) { + const keyType = testVariable.tssLib.keyType as KeyType; + + after(async () => { + await resetAccount(testVariable.email); + }); + + it("#recover Tss key using 2 factors key, import tss key to new oauth login", async function () { const sfaResult = await loginWithSFA({ network: WEB3AUTH_NETWORK.DEVNET, manualSync: testVariable.manualSync, email: testVariable.email, + legacyFlag: testVariable.legacyFlag, storageInstance, + tssLib: testVariable.tssLib, + }); + const coreKitInstance = await newCoreKitInstance(testVariable.email); // Create 2 factors which will be used to recover tss key. @@ -60,45 +71,48 @@ export const ImportSFATest = async (testVariable: ImportKeyTestVariable) => { } // Export key and logout. - const exportedTssKey1 = await coreKitInstance._UNSAFE_exportTssKey(); - await coreKitInstance.logout(); + const exportedTssKey1 = await coreKitInstance._UNSAFE_exportTssKey(keyType); + let exportEd25519Seed : string | undefined = undefined + if (keyType === KeyType.ed25519) { + const edResult = await coreKitInstance._UNSAFE_exportTssEd25519Seed() + exportEd25519Seed = edResult.toString("hex") + } // Recover key from any two factors. - const recoveredTssKey = await coreKitInstance._UNSAFE_recoverTssKey([factorKeyDevice, factorKeyRecovery]); + const recoveredTssKey = await coreKitInstance._UNSAFE_recoverTssKey([factorKeyDevice, factorKeyRecovery], keyType); assert.strictEqual(recoveredTssKey, exportedTssKey1); - assert.strictEqual(sfaResult.finalKeyData.privKey,recoveredTssKey); - // sfa key should be empty after import to mpc - const sfaResult2 = await loginWithSFA({ - network: WEB3AUTH_NETWORK.DEVNET, - manualSync: testVariable.manualSync, - email: testVariable.email, - storageInstance, - }); - assert.strictEqual(sfaResult2.finalKeyData.privKey, ""); - - const coreKitInstance2 = await newCoreKitInstance(testVariable.email); - const tssKey2 = await coreKitInstance2._UNSAFE_exportTssKey(); - // core kit should have same sfa key which was imported before - assert.strictEqual(tssKey2, exportedTssKey1); - assert.strictEqual(sfaResult.finalKeyData.privKey, tssKey2); - - - }); - - await afterTest(); - t.afterEach(function () { - return console.info("finished running recovery test"); - }); - t.after(function () { - return console.info("finished running recovery tests"); + assert.strictEqual(sfaResult.finalKeyData.privKey, exportEd25519Seed ?? exportedTssKey1); + // sfa key should be empty after import to mpc + const sfaResult2 = await loginWithSFA({ + network: WEB3AUTH_NETWORK.DEVNET, + manualSync: testVariable.manualSync, + email: testVariable.email, + storageInstance, + tssLib: testVariable.tssLib, + legacyFlag: testVariable.legacyFlag, + }); + assert.strictEqual(sfaResult2.finalKeyData.privKey, ""); + + const coreKitInstance2 = await newCoreKitInstance(testVariable.email); + + const tssKey2 = await coreKitInstance2._UNSAFE_exportTssKey(keyType); + + exportEd25519Seed = undefined + if (keyType === KeyType.ed25519) { + const edResult = await coreKitInstance2._UNSAFE_exportTssEd25519Seed() + exportEd25519Seed = edResult.toString("hex") + } + // core kit should have same sfa key which was imported before + assert.strictEqual(tssKey2, exportedTssKey1); + assert.strictEqual(sfaResult.finalKeyData.privKey, exportEd25519Seed ?? tssKey2); }); }); }; const variable: ImportKeyTestVariable[] = [ - { manualSync: false, email: generateRandomEmail(), tssLib: tssLibDKLS }, - { manualSync: true, email: generateRandomEmail(), tssLib: tssLibDKLS }, - { manualSync: false, email: generateRandomEmail(), tssLib: tssLibFROST }, + { manualSync: false, email: generateRandomEmail(), tssLib: tssLibDKLS, legacyFlag: false }, + { manualSync: true, email: generateRandomEmail(), tssLib: tssLibDKLS , legacyFlag: false}, + { manualSync: false, email: generateRandomEmail(), tssLib: tssLibFROST, legacyFlag: true }, ]; variable.forEach(async (testVariable) => { From bc907ddf445930ed0ec9fd4440e84a40254311af Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 13 Feb 2025 16:15:37 +0800 Subject: [PATCH 08/16] fix: import recovery test --- package-lock.json | 2 +- tests/importRecovery.spec.ts | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index bda8a48b..933e5d5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3906,7 +3906,7 @@ "node_modules/@tkey/tss": { "version": "15.2.1-alpha.0", "resolved": "file:../tkey/packages/tss/tkey-tss-15.2.1-alpha.0.tgz", - "integrity": "sha512-PWETbhENWKAkRacaKE1ftP+X74XnXIn6vw5COvKBlX2ClZMrZwfUYr/nS7McX3zNhfhHkDMHjarij++QV5Vnog==", + "integrity": "sha512-qc+aZ3PnAkbUZlcbKAcFJ5rVmnqZuJnFhCp/y031BOJWmCH+Lw4wwlSAqrzH9Z9NEi+D7QnOS8r2eay4dTd56g==", "license": "ISC", "dependencies": { "@tkey/common-types": "^15.2.1-alpha.0", diff --git a/tests/importRecovery.spec.ts b/tests/importRecovery.spec.ts index 7efd8fc1..d78e0122 100644 --- a/tests/importRecovery.spec.ts +++ b/tests/importRecovery.spec.ts @@ -9,7 +9,6 @@ import { bufferToElliptic, criticalResetAccount, newCoreKitLogInInstance } from import { getKeyCurve } from "@toruslabs/torus.js"; import { KeyType, Point } from "@tkey/common-types"; import { MockStorageLayer } from "@tkey/storage-layer-torus"; -import { BN } from "bn.js"; type ImportKeyTestVariable = { manualSync?: boolean; @@ -22,8 +21,8 @@ type ImportKeyTestVariable = { const storageInstance = new MemoryStorage(); // use mockStorageLayer, hence resetAccount is not required. -const mockStorageLayer = new MockStorageLayer(); export const ImportTest = async (testVariable: ImportKeyTestVariable) => { + const mockStorageLayer = new MockStorageLayer(); async function newCoreKitInstance(email: string, importTssKey?: string) { return newCoreKitLogInInstance({ network: WEB3AUTH_NETWORK.DEVNET, @@ -37,7 +36,7 @@ export const ImportTest = async (testVariable: ImportKeyTestVariable) => { }); } - describe(`import recover tss key : ${testVariable.manualSync}, testVariable: ${testVariable}`, async function (t) { + describe(`import recover tss key manual sync: ${testVariable.manualSync}, testVariable: ${JSON.stringify(testVariable)}`, async function (t) { it("#recover Tss key using 2 factors key, import tss key to new oauth login", async function () { const coreKitInstance = await newCoreKitInstance(testVariable.email); @@ -88,8 +87,6 @@ export const ImportTest = async (testVariable: ImportKeyTestVariable) => { const exportedTssKey3 = await coreKitInstance3._UNSAFE_exportTssKey(keyType); const tssCurve = getKeyCurve(keyType); const exportedPub = tssCurve.keyFromPrivate(exportedTssKey3).getPublic(); - console.log(exportedPub.encodeCompressed("hex")) - console.log(tssPubkey.encodeCompressed("hex")) assert(tssPubkey.eq(exportedPub)); // Check exported key corresponds to pub key for account index > 0. @@ -105,9 +102,9 @@ export const ImportTest = async (testVariable: ImportKeyTestVariable) => { }; const variable: ImportKeyTestVariable[] = [ - // { manualSync: false, email: "emailexport", importKeyEmail: "emailimport", tssLib: tssLibDKLS }, - // { manualSync: true, email: "emailexport", importKeyEmail: "emailimport", tssLib: tssLibDKLS }, - { manualSync: false, email: "emailexport_ed25519", importKeyEmail: "emailimport_ed25519", tssLib: tssLibFROST }, + { manualSync: false, email: "emailexport", importKeyEmail: "emailimport", tssLib: tssLibDKLS }, + { manualSync: true, email: "emailexport", importKeyEmail: "emailimport", tssLib: tssLibDKLS }, + // { manualSync: false, email: "emailexport_ed25519--1", importKeyEmail: "emailimport_ed25519--1", tssLib: tssLibFROST }, ]; variable.forEach(async (testVariable) => { From 4422e74f6447663f567d46c6cd316c830b96f451 Mon Sep 17 00:00:00 2001 From: ieow Date: Sat, 22 Feb 2025 04:26:26 +0800 Subject: [PATCH 09/16] feat: refactor setTssTag --- package-lock.json | 2 +- src/mpcCoreKit.ts | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 933e5d5a..a370a042 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3906,7 +3906,7 @@ "node_modules/@tkey/tss": { "version": "15.2.1-alpha.0", "resolved": "file:../tkey/packages/tss/tkey-tss-15.2.1-alpha.0.tgz", - "integrity": "sha512-qc+aZ3PnAkbUZlcbKAcFJ5rVmnqZuJnFhCp/y031BOJWmCH+Lw4wwlSAqrzH9Z9NEi+D7QnOS8r2eay4dTd56g==", + "integrity": "sha512-ftGsqLxlc3MeswdtJX+vxusnFXFZyNQMz7QLkjOmXUp6qlGMAEF66/UfRwdfs1U8xjsdL31XoD5XKLWMNNVZPQ==", "license": "ISC", "dependencies": { "@tkey/common-types": "^15.2.1-alpha.0", diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 703ac830..7697b549 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -255,7 +255,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { public getTssShare(args: { keyType: KeyType; factorkey: BN; accountIndex?: number }) { const { keyType, factorkey, accountIndex } = args; return this.tkey.getTSSShare(factorkey, { - tssTag: TSS_TAG_DEFAULT, keyType, accountIndex: accountIndex === undefined ? this.state.accountIndex : accountIndex, }); @@ -764,7 +763,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { * Get public key point. */ public getPubKeyPoint(keyType: KeyType, accountIndex?: number): Point { - const tssPubKey = this.tkey.getTSSPub(keyType, TSS_TAG_DEFAULT, accountIndex === undefined ? this.state.accountIndex : accountIndex); + const tssPubKey = this.tkey.getTSSPub(keyType, accountIndex === undefined ? this.state.accountIndex : accountIndex); return tssPubKey; } @@ -967,7 +966,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } const authSignatures = await this.getSessionSignatures(); - await this.tKey.deleteFactorPub({ factorKey: this.state.factorKey, deleteFactorPub: factorPub, authSignatures, tssTag: TSS_TAG_DEFAULT }); + await this.tKey.deleteFactorPub({ factorKey: this.state.factorKey, deleteFactorPub: factorPub, authSignatures }); const factorPubHex = fpp.toSEC1(factorKeyCurve, true).toString("hex"); const allDesc = this.tkey.metadata.getShareDescription(); const keyDesc = allDesc[factorPubHex]; @@ -1097,7 +1096,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { factorKey: this.state.factorKey, authSignatures: this.state.signatures, keyType, - tssTag: TSS_TAG_DEFAULT, }); const accountNonce = this.getAccountNonce(); @@ -1124,7 +1122,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const exportEd25519Seed = await this.tKey._UNSAFE_exportTssEd25519Seed({ factorKey: this.state.factorKey, authSignatures: this.state.signatures, - tssTag: TSS_TAG_DEFAULT, }); return exportEd25519Seed; @@ -1538,7 +1535,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { newFactorPub, newTSSIndex: newFactorTSSIndex, refreshShares: this.state.tssShareIndex !== newFactorTSSIndex, // Refresh shares if we have a new factor key index. - tssTag: TSS_TAG_DEFAULT, }); } From 214e1e9d33d9676dbad0f0ba7b8a022d78bab231 Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 27 Feb 2025 08:02:31 +0800 Subject: [PATCH 10/16] fix: comments remove unsed code and comment update new user comments and flow update comment --- src/interfaces.ts | 10 ++++ src/mpcCoreKit.ts | 32 +++-------- src/utils.ts | 55 +++++++++---------- ...ltiCurveTest.ts => multiCurveTest.spec.ts} | 30 ++++++++-- 4 files changed, 71 insertions(+), 56 deletions(-) rename tests/{multiCurveTest.ts => multiCurveTest.spec.ts} (74%) diff --git a/src/interfaces.ts b/src/interfaces.ts index 39d13bc9..8ace2c16 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -549,6 +549,16 @@ export interface EthereumSigner { getPublic: () => Promise; } +export interface Bip340Signer { + sign: (msgHash: Buffer) => Promise; + getPublic: () => Promise; +} + +export interface Ed25519Signer { + sign: (msgHash: Buffer) => Promise; + getPublic: () => Promise; +} + export type StateEmitterEvents = { LOGOUT: () => void; }; diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 7697b549..34478c84 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -208,10 +208,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return this.options.uxMode === UX_MODE.REDIRECT; } - // private get useClientGeneratedTSSKey(): boolean { - // return this._sigType === "ed25519" && this.options.useClientGeneratedTSSKey === undefined ? true : !!this.options.useClientGeneratedTSSKey; - // } - public getSupportedSigTypes(): Array { return Array.from(this.supportedSigTypes); } @@ -318,11 +314,11 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { this.resetState(); if (params.rehydrate === undefined) params.rehydrate = true; - const nodeDetails = fetchLocalConfig(this.options.web3AuthNetwork, KeyType.ed25519); - // multicurve only support for secp256k1 torus/ sss const spKeyType = this.getServiceProviderKeyType(); + const nodeDetails = fetchLocalConfig(this.options.web3AuthNetwork, spKeyType); + this.torusSp = new TSSTorusServiceProvider({ customAuthArgs: { web3AuthClientId: this.options.web3AuthClientId, @@ -923,7 +919,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return this.sign_frost({ data: Buffer.from(data), keyType: KeyType.secp256k1, sigType: SIG_TYPE.BIP340, frostlib, keyTweak: opts?.keyTweak }); } - public async signEd25519(data: Uint8Array, opts?: { hashed?: boolean }) { + public async signEd25519(data: Uint8Array) { if (!this.supportedCurveKeyTypes.has(KeyType.ed25519)) { throw CoreKitError.default(`ed25519 KeyTYpe is not supported, please configure ed25519 curve key type `); } @@ -931,9 +927,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.default(`ed25519 is not supported, please configure tssLib with ed25519 signature type `); } - if (opts?.hashed) { - throw CoreKitError.default(`hashed data not supported for bip340`); - } await this.loadTssWasm(SIG_TYPE.ED25519); const frostlib = this.wasmLib[SIG_TYPE.ED25519]; if (!frostlib) { @@ -1216,18 +1209,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } } - // private async importTssKey(tssKey: string, factorPub: Point, newTSSIndex: TssShareType = TssShareType.DEVICE): Promise { - // if (!this.state.signatures) { - // throw CoreKitError.signaturesNotPresent("Signatures not present in state when importing tss key."); - // } - - // const keyType = this._keyType - // await this.tKey.importTssKey( - // { tssTag: this.tKey.tssTag, importKey: Buffer.from(tssKey, "hex"), factorPubs: [factorPub], newTSSIndexes: [newTSSIndex], tssKeyType: keyType }, - // { authSignatures: this.state.signatures } - // ); - // } - private getTssNonce(keyType: KeyType): number { const tssData = this.getTssData({ keyType }); if (tssData.tssNonce === undefined) { @@ -1273,7 +1254,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (this.supportedCurveKeyTypes.has(KeyType.ed25519)) { const importTssBufEd25519 = importTssKey.ed25519 ? Buffer.from(importTssKey.ed25519, "hex") : undefined; - // check if key is in the tsslib and keytype exists + // factorPub and tssIndex are not allowed as tkey tss will get from tss data of existing curve await this.tKey.initializeTss({ importKey: importTssBufEd25519, tssKeyType: KeyType.ed25519, @@ -1283,7 +1264,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { }, }); } - } else { + } else if (this.supportedCurveKeyTypes.has(KeyType.ed25519)) { + // for case where only ed25519 is configured, factorPub, and index is required const importTssBuf = importTssKey.ed25519 ? Buffer.from(importTssKey.ed25519, "hex") : undefined; await this.tKey.initializeTss({ importKey: importTssBuf, @@ -1295,6 +1277,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { authSignatures: this.state.signatures, }, }); + } else { + throw CoreKitError.default("Invalid or unsupported type"); } // Finalize initialization. diff --git a/src/utils.ts b/src/utils.ts index 74b6de28..896183b3 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -9,7 +9,8 @@ import { eddsa as EDDSA } from "elliptic"; import loglevel from "loglevel"; import { DELIMITERS, SCALAR_LEN } from "./constants"; -import { CoreKitSigner, EthereumSigner, IAsyncStorage, IStorage } from "./interfaces"; +import { Bip340Signer, Ed25519Signer, EthereumSigner, IAsyncStorage, IStorage } from "./interfaces"; +import { Web3AuthMPCCoreKit } from "./mpcCoreKit"; export const ed25519 = () => { return new EDDSA("ed25519"); @@ -195,53 +196,51 @@ export function sigToRSV(sig: Buffer) { return { r: sig.subarray(0, 32), s: sig.subarray(32, 64), v: sig[64] }; } -export function makeEthereumSigner(kit: CoreKitSigner): EthereumSigner { - if (kit.keyType !== KeyType.secp256k1) { - throw new Error(`Invalid key type: expected secp256k1, got ${kit.keyType}`); +export function makeEthereumSigner(kit: Web3AuthMPCCoreKit): EthereumSigner { + if (!kit.getSupportedCurveKeyTypes().includes(KeyType.secp256k1)) { + throw new Error(`Invalid key type: secp256k1 is not configured`); } return { sign: async (msgHash: Buffer) => { - const sig = await kit.sign(msgHash, { hashed: true }); + const sig = await kit.signECDSA(msgHash, { hashed: true }); return sigToRSV(sig); }, getPublic: async () => { - const pk = Point.fromSEC1(secp256k1, kit.getPubKey().toString("hex")); + const pk = Point.fromSEC1(secp256k1, kit.getPubKey(KeyType.secp256k1).toString("hex")); return pk.toSEC1(secp256k1).subarray(1); }, }; } -// export function makeBip340Signer(kit: CoreKitSigner): EthereumSigner { -// if (kit.keyType !== KeyType.secp256k1) { -// throw new Error(`Invalid key type: expected secp256k1, got ${kit.keyType}`); -// } -// return { -// sign: async (msgHash: Buffer) => { -// const sig = await kit.sign(msgHash, { hashed: true }); -// return sigToRSV(sig); -// }, -// getPublic: async () => { -// const pk = Point.fromSEC1(secp256k1, kit.getPubKey().toString("hex")); -// return pk.toSEC1(secp256k1).subarray(1); -// }, -// }; -// } - -export function makeEd25519Signer(kit: CoreKitSigner): EthereumSigner { - if (kit.keyType !== KeyType.secp256k1) { - throw new Error(`Invalid key type: expected secp256k1, got ${kit.keyType}`); +export function makeBip340Signer(kit: Web3AuthMPCCoreKit): Bip340Signer { + if (!kit.getSupportedCurveKeyTypes().includes(KeyType.secp256k1)) { + throw new Error(`Invalid key type: secp256k1 is not configured`); } + return { sign: async (msgHash: Buffer) => { - const sig = await kit.sign(msgHash, { hashed: true }); - return sigToRSV(sig); + return kit.signBip340(msgHash, { hashed: false }); }, getPublic: async () => { - const pk = Point.fromSEC1(secp256k1, kit.getPubKey().toString("hex")); + const pk = Point.fromSEC1(secp256k1, kit.getPubKey(KeyType.secp256k1).toString("hex")); return pk.toSEC1(secp256k1).subarray(1); }, }; } +export function makeEd25519Signer(kit: Web3AuthMPCCoreKit): Ed25519Signer { + if (!kit.getSupportedCurveKeyTypes().includes(KeyType.ed25519)) { + throw new Error(`Invalid key type: ed25519 is not configured`); + } + return { + sign: async (msgHash: Buffer) => { + return kit.signEd25519(msgHash); + }, + getPublic: async () => { + return kit.getPubKeyEd25519(); + }, + }; +} + export const log = loglevel.getLogger("mpc-core-kit"); log.disableAll(); diff --git a/tests/multiCurveTest.ts b/tests/multiCurveTest.spec.ts similarity index 74% rename from tests/multiCurveTest.ts rename to tests/multiCurveTest.spec.ts index e73a95ee..17a5d031 100644 --- a/tests/multiCurveTest.ts +++ b/tests/multiCurveTest.spec.ts @@ -1,11 +1,11 @@ -import { COREKIT_STATUS } from './../src/interfaces'; +import { COREKIT_STATUS } from '../src/interfaces'; import dklslib from "@toruslabs/tss-dkls-lib"; import frostLib from "@toruslabs/tss-frost-lib"; import frostBip340lib from "@toruslabs/tss-frost-lib-bip340"; import { expect } from "chai"; import { describe, it } from "node:test"; -import { MemoryStorage, sigToRSV, WEB3AUTH_NETWORK, Web3AuthMPCCoreKit } from "src"; +import { makeBip340Signer, makeEd25519Signer, makeEthereumSigner, MemoryStorage, sigToRSV, WEB3AUTH_NETWORK, Web3AuthMPCCoreKit } from "src"; import { mockLogin2 } from "./setup"; import { KeyType } from '@tkey/common-types'; import { BN } from 'bn.js'; @@ -29,7 +29,6 @@ const mockSL = new MockStorageLayer({ }); describe("multiCurveTest", () => { - // const newCoreKitInstance = () => new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", @@ -64,10 +63,33 @@ describe("multiCurveTest", () => { instance.addTssLibs([frostLib]); - const result3 = await instance.signEd25519(Buffer.from(message), { hashed: false }) + const result3 = await instance.signEd25519(Buffer.from(message)) const valided25519 = ed25519.verify(bytesToHex(result3), bytesToHex(Buffer.from(message)), bytesToHex( new Uint8Array(instance.getPubKeyEd25519()) ) ) expect(valided25519).eq(true); + + const ethSigner = makeEthereumSigner(instance) + const ethSignerPubKey = await ethSigner.getPublic(); + const ethSignerResult = await ethSigner.sign(Buffer.from(hash)) + const validsethSignerResult = secp256k1.verify({ + r: bytesToNumberBE(ethSignerResult.r), + s: bytesToNumberBE(ethSignerResult.s), + }, bytesToHex(hash), "04"+bytesToHex(ethSignerPubKey)); + expect(validsethSignerResult).eq(true); + + + const bip340Signer = makeBip340Signer(instance) + const bip340SignerResult = await bip340Signer.sign(Buffer.from(utf8ToBytes(message))); + + + const validBip340SignerResult = bip340.verify(bip340SignerResult, bytesToHex(utf8ToBytes(message)), bytesToHex(instance.getPubKeyBip340())); + expect(validBip340SignerResult).eq(true); + + const ed25519Signer = makeEd25519Signer(instance) + const ed25519SignerResult = await ed25519Signer.sign(Buffer.from(utf8ToBytes(message))) + const validEd25519SignerResult = ed25519.verify(ed25519SignerResult, bytesToHex(Buffer.from(message)), bytesToHex( new Uint8Array(instance.getPubKeyEd25519()) ) ) + expect(validEd25519SignerResult).eq(true); + } it("should able to initialize with multiple curve/ tsslib", async () => { From 7723c8af7af156099319a4e77029862cc34009ed Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 27 Feb 2025 08:16:02 +0800 Subject: [PATCH 11/16] fix: get keyType and SigType from frostLib --- src/mpcCoreKit.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 34478c84..0023c699 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -916,7 +916,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!frostlib) { throw CoreKitError.default(`frostlib not loaded for ed25519`); } - return this.sign_frost({ data: Buffer.from(data), keyType: KeyType.secp256k1, sigType: SIG_TYPE.BIP340, frostlib, keyTweak: opts?.keyTweak }); + if (frostlib.keyType !== KeyType.secp256k1) { + throw CoreKitError.default("frostlib keyType not matched"); + } + return this.sign_frost({ data: Buffer.from(data), frostlib, keyTweak: opts?.keyTweak }); } public async signEd25519(data: Uint8Array) { @@ -932,7 +935,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (!frostlib) { throw CoreKitError.default(`frostlib not loaded for ed25519`); } - return this.sign_frost({ data: Buffer.from(data), keyType: KeyType.ed25519, sigType: SIG_TYPE.ED25519, frostlib }); + if (frostlib.keyType !== KeyType.ed25519) { + throw CoreKitError.default(`frostlib keyType not matched - forstlib keyType ${frostlib.keyType}`); + } + return this.sign_frost({ data: Buffer.from(data), frostlib }); } // mutation function @@ -1672,14 +1678,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } } - private async sign_frost(args: { - data: Buffer; - keyTweak?: BN; - keyType: KeyType; - sigType: WEB3AUTH_SIG_TYPE; - frostlib: FrostWasmLibEd25519 | FrostWasmLibBip340; - }): Promise { - const { data, keyTweak, keyType, sigType, frostlib } = args; + private async sign_frost(args: { data: Buffer; keyTweak?: BN; frostlib: FrostWasmLibEd25519 | FrostWasmLibBip340 }): Promise { + const { data, keyTweak, frostlib } = args; + + const keyType = frostlib.keyType as KeyType; + const sigType = frostlib.sigType as WEB3AUTH_SIG_TYPE; + const nodeDetails = fetchLocalConfig(this.options.web3AuthNetwork, keyType, sigType); if (!nodeDetails.torusNodeTSSEndpoints) { throw CoreKitError.default("could not fetch tss node endpoints"); From 2a4322d76dfd022ed8c137f0c4ba53ea7b3482f6 Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 27 Feb 2025 08:38:41 +0800 Subject: [PATCH 12/16] fix: update interface and comment rename function name --- src/interfaces.ts | 41 ++++++++++++++++++++++++++++-------- src/mpcCoreKit.ts | 4 ++-- src/utils.ts | 4 ++-- tests/bip340.spec.ts | 2 +- tests/ed25519.spec.ts | 2 +- tests/multiCurveTest.spec.ts | 4 ++-- 6 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/interfaces.ts b/src/interfaces.ts index 8ace2c16..1850a871 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -478,21 +478,44 @@ export interface ICoreKit { commitChanges(): Promise; /** - * Create a signature for the given data. + * Create a SECP256K1 ECDSA signature for the given data. + * will throw if secp256k1 is not configured as supported keyType + * will thrwo if dkls lib is not added prior signing * * Options: * - hashed: The data is already hashed. Do not hash again. Only works for ecdsa-secp256k1. * - secp256k1Precompute: Provide a precomputed client for faster signing. Only works for ecdsa-secp256k1. + */ + signECDSA( + data: Buffer, + opts?: { + hashed?: boolean; + secp256k1Precompute?: Secp256k1PrecomputedClient; + } + ): Promise; + + /** + * Create a BIP340 signature for the given data. + * will throw if secp256k1 is not configured as supported keyType + * will thrwo if bip340 frost lib is not added prior signing + * + * Options: * - keyTweak: Provide a bip340 key tweak. Only works for bip340. */ - // sign( - // data: Buffer, - // opts?: { - // hashed?: boolean; - // secp256k1Precompute?: Secp256k1PrecomputedClient; - // keyTweak?: BN; - // } - // ): Promise; + signBIP340( + data: Buffer, + opts?: { + keyTweak?: BN; + } + ): Promise; + + /** + * Create a ED25519 signature for the given data. + * will throw if ed25519 is not configured as supported keyType + * will thrwo if ed25519 frost lib is not added prior signing + * + */ + signED25519(data: Buffer): Promise; /** * WARNING: Use with caution. This will export the private signing key. diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 0023c699..4d67f10a 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -900,7 +900,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return Buffer.concat([sig.r, sig.s, Buffer.from([sig.v])]); } - public async signBip340(data: Uint8Array, opts?: { hashed?: boolean; keyTweak?: BN }) { + public async signBIP340(data: Uint8Array, opts?: { hashed?: boolean; keyTweak?: BN }) { if (!this.supportedCurveKeyTypes.has(KeyType.secp256k1)) { throw CoreKitError.default(`secp256k1 KeyTYpe is not supported, please configure secp256k1 curve key type `); } @@ -922,7 +922,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return this.sign_frost({ data: Buffer.from(data), frostlib, keyTweak: opts?.keyTweak }); } - public async signEd25519(data: Uint8Array) { + public async signED25519(data: Uint8Array) { if (!this.supportedCurveKeyTypes.has(KeyType.ed25519)) { throw CoreKitError.default(`ed25519 KeyTYpe is not supported, please configure ed25519 curve key type `); } diff --git a/src/utils.ts b/src/utils.ts index 896183b3..bf92fae8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -219,7 +219,7 @@ export function makeBip340Signer(kit: Web3AuthMPCCoreKit): Bip340Signer { return { sign: async (msgHash: Buffer) => { - return kit.signBip340(msgHash, { hashed: false }); + return kit.signBIP340(msgHash, { hashed: false }); }, getPublic: async () => { const pk = Point.fromSEC1(secp256k1, kit.getPubKey(KeyType.secp256k1).toString("hex")); @@ -234,7 +234,7 @@ export function makeEd25519Signer(kit: Web3AuthMPCCoreKit): Ed25519Signer { } return { sign: async (msgHash: Buffer) => { - return kit.signEd25519(msgHash); + return kit.signED25519(msgHash); }, getPublic: async () => { return kit.getPubKeyEd25519(); diff --git a/tests/bip340.spec.ts b/tests/bip340.spec.ts index 1c97e723..3ee06011 100644 --- a/tests/bip340.spec.ts +++ b/tests/bip340.spec.ts @@ -151,7 +151,7 @@ variable.forEach((testVariable) => { const msg = "hello world"; const msgBuffer = Buffer.from(msg); - const signature = await coreKitInstance.signBip340(msgBuffer); + const signature = await coreKitInstance.signBIP340(msgBuffer); const pk = coreKitInstance.getPubKeyBip340(); const valid = bip340.verify(signature, msgBuffer, pk); assert(valid); diff --git a/tests/ed25519.spec.ts b/tests/ed25519.spec.ts index 599d6ef5..227abb14 100644 --- a/tests/ed25519.spec.ts +++ b/tests/ed25519.spec.ts @@ -148,7 +148,7 @@ variable.forEach((testVariable) => { const msg = "hello world"; const msgBuffer = Buffer.from(msg); - const signature = ed25519().makeSignature((await coreKitInstance.signEd25519(msgBuffer)).toString("hex")); + const signature = ed25519().makeSignature((await coreKitInstance.signED25519(msgBuffer)).toString("hex")); const valid = ed25519().verify(msgBuffer, signature, coreKitInstance.getPubKeyEd25519()); assert(valid); }); diff --git a/tests/multiCurveTest.spec.ts b/tests/multiCurveTest.spec.ts index 17a5d031..4a1893b4 100644 --- a/tests/multiCurveTest.spec.ts +++ b/tests/multiCurveTest.spec.ts @@ -56,14 +56,14 @@ describe("multiCurveTest", () => { expect(validsecp256k1).eq(true); instance.addTssLibs([frostBip340lib]); - const result2 = await instance.signBip340( Buffer.from(utf8ToBytes(message)), {hashed: false}) + const result2 = await instance.signBIP340( Buffer.from(utf8ToBytes(message)), {hashed: false}) const validb340 = bip340.verify(bytesToHex(result2), bytesToHex(utf8ToBytes(message)), bytesToHex(instance.getPubKeyBip340())); expect(validb340).eq(true); instance.addTssLibs([frostLib]); - const result3 = await instance.signEd25519(Buffer.from(message)) + const result3 = await instance.signED25519(Buffer.from(message)) const valided25519 = ed25519.verify(bytesToHex(result3), bytesToHex(Buffer.from(message)), bytesToHex( new Uint8Array(instance.getPubKeyEd25519()) ) ) expect(valided25519).eq(true); From 0415c0ee997a00319718f5db8d11f93c9cfa1028 Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 27 Feb 2025 08:53:10 +0800 Subject: [PATCH 13/16] feat: break getTssData to 2 function for clearity --- src/mpcCoreKit.ts | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 4d67f10a..8b953703 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -256,14 +256,18 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { }); } - public getTssData(args: { skipThrow?: boolean; keyType: KeyType }) { - const result = this.tkey.metadata.getTssData(args.keyType, TSS_TAG_DEFAULT); - if (!result && !args.skipThrow) { - throw CoreKitError.noMetadataFound(); + public getTssData(keyType: KeyType) { + const result = this.getTssDataNotThrow(keyType); + if (!result) { + throw CoreKitError.default("Legacy mode only support single curve, please congfiure with correct keyType"); } return result; } + public getTssDataNotThrow(keyType: KeyType) { + return this.tkey.metadata.getTssData(keyType, TSS_TAG_DEFAULT); + } + // RecoverTssKey only valid for user that enable MFA where user has 2 type shares : // TssShareType.DEVICE and TssShareType.RECOVERY // if the factors key provided is the same type recovery will not works @@ -591,7 +595,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (this.options.legacyFlag) { const spKeyType = this.getServiceProviderKeyType(); // Check for existing curve in tssData for legacy mode - const tssData = this.getTssData({ keyType: spKeyType, skipThrow: true }); + const tssData = this.getTssDataNotThrow(spKeyType); if (!tssData) throw CoreKitError.default("Legacy mode only support single curve, please congfiure with correct keyType"); } @@ -701,7 +705,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when getting tss factor public key."); } const firstKeyType = this.getSupportedCurveKeyTypes()[0]; - const tssData = this.getTssData({ keyType: firstKeyType }); + const tssData = this.getTssData(firstKeyType); const factorPubsList = tssData.factorPubs; return factorPubsList.map((factorPub) => factorPub.toSEC1(factorKeyCurve, true).toString("hex")); }; @@ -831,7 +835,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const clientIndex = parties - 1; // 1. setup // generate endpoints for servers - const tssData = this.getTssData({ keyType }); + const tssData = this.getTssData(keyType); const { nodeIndexes } = await this.torusSp.getTSSPubKey(this.tKey.tssTag, tssData.tssNonce, keyType); const { endpoints, @@ -948,7 +952,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when deleting a factor."); } const firstKeyType = this.getSupportedCurveKeyTypes()[0]; - const tssData = this.getTssData({ keyType: firstKeyType }); + const tssData = this.getTssData(firstKeyType); if (!tssData.factorPubs) { throw CoreKitError.factorPubsMissing(); } @@ -1216,7 +1220,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } private getTssNonce(keyType: KeyType): number { - const tssData = this.getTssData({ keyType }); + const tssData = this.getTssData(keyType); if (tssData.tssNonce === undefined) { throw CoreKitError.tssNoncesMissing(`tssNonce not present for tag ${this.tKey.tssTag}`); } @@ -1321,8 +1325,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (this.options.legacyFlag) { const spKeyType = this.getServiceProviderKeyType(); // Check for existing curve in tssData for legacy mode - const tssData = this.getTssData({ keyType: spKeyType, skipThrow: true }); - if (!tssData) throw CoreKitError.default("Legacy mode only support single curve, please congfiure with correct keyType"); + // the function below will throw if tss data is not available + this.getTssData(spKeyType); } if (this.options.disableHashedFactorKey) { @@ -1358,7 +1362,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { let newCurveKeyType = false; for (const keyType of this.supportedCurveKeyTypes) { - const tssData = this.getTssData({ skipThrow: true, keyType }); + const tssData = this.getTssDataNotThrow(keyType); if (!tssData) { newCurveKeyType = true; } @@ -1368,7 +1372,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { this.atomicSync(async () => { // check for missing curve and initialize it for (const keyType of this.supportedCurveKeyTypes) { - const tssData = this.getTssData({ skipThrow: true, keyType }); + const tssData = this.getTssDataNotThrow(keyType); if (!tssData) { await this.tKey.initializeTss({ tssKeyType: keyType, @@ -1501,7 +1505,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { private async copyOrCreateShare(newFactorTSSIndex: number, newFactorPub: Point) { this.checkReady(); const firstKeyType = this.getSupportedCurveKeyTypes()[0]; - const tssData = this.getTssData({ keyType: firstKeyType }); + const tssData = this.getTssData(firstKeyType); if (!tssData.factorPubs || !Array.isArray(tssData.factorPubs)) { throw CoreKitError.factorPubsMissing("'factorPubs' is missing in the metadata. Failed to copy factor public key."); } From d4ebfbc191130abb40e86291b48c443938254d4b Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 27 Feb 2025 16:18:14 +0800 Subject: [PATCH 14/16] fix: address comment fix ed25519 with accountIndex 0 fix useClientGeneratedTSSKey fix typo --- src/mpcCoreKit.ts | 14 +++++++------- tests/backwardCompatible.spec.ts | 2 -- tests/setup.ts | 3 --- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 8b953703..6ad5d659 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -482,12 +482,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { throw CoreKitError.invalidConfig("Cannot import TSS key and register SFA key at the same time."); } - const fisrtKeyType = this.getSupportedCurveKeyTypes()[0]; + const firstKeyType = this.getSupportedCurveKeyTypes()[0]; try { // prefetch tss pub keys. const prefetchTssPubs = []; for (let i = 0; i < prefetchTssPublicKeys; i++) { - prefetchTssPubs.push(this.torusSp.getTSSPubKey(this.tkey.tssTag, i, fisrtKeyType)); + prefetchTssPubs.push(this.torusSp.getTSSPubKey(this.tkey.tssTag, i, firstKeyType)); } // get postbox key. @@ -519,7 +519,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const existingSFAKey = loginResponse.finalKeyData.privKey.padStart(64, "0"); await this.setupTkey({ - providedImportKey: { [fisrtKeyType]: existingSFAKey }, + providedImportKey: { [firstKeyType]: existingSFAKey }, importingSFAKey: true, sfaLoginResponse: loginResponse, userInfo: { ...parseToken(idToken), verifier, verifierId }, @@ -778,7 +778,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } const tssCurve = getKeyCurve(KeyType.ed25519); - // ed25519 only support account index 0 ? + if (this.state.accountIndex !== 0) throw CoreKitError.default("Ed25519 only support account index 0"); const p = this.getPubKeyPoint(KeyType.ed25519, 0).toEllipticPoint(tssCurve); return ed25519().keyFromPublic(p).getPublic(); } @@ -1084,9 +1084,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { * * Exports the private key scalar for the current account index. * + * @param keyType - export final tsskey of designated keyType + * * For signature type ed25519, consider using _UNSAFE_exportTssEd25519Seed. */ - // TODO : should return all keyType final keys? public async _UNSAFE_exportTssKey(keyType: KeyType): Promise { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when exporting tss key."); @@ -1170,14 +1171,13 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { const existingUser = await this.isMetadataPresent(this.state.postBoxKey); const importKey = providedImportKey ?? {}; if (!existingUser) { - // if (!importKey && this.useClientGeneratedTSSKey) { const keyTypes = this.getSupportedCurveKeyTypes(); for (const keyType of keyTypes) { if (!importKey[keyType]) { if (keyType === KeyType.ed25519) { const k = generateEd25519Seed(); importKey.ed25519 = k.toString("hex"); - } else if (keyType === KeyType.secp256k1) { + } else if (keyType === KeyType.secp256k1 && !!this.options.useClientGeneratedTSSKey) { const k = secp256k1.genKeyPair().getPrivate(); importKey.secp256k1 = scalarBNToBufferSEC1(k).toString("hex"); } else { diff --git a/tests/backwardCompatible.spec.ts b/tests/backwardCompatible.spec.ts index 0c1b41e9..2bfe3eec 100644 --- a/tests/backwardCompatible.spec.ts +++ b/tests/backwardCompatible.spec.ts @@ -75,8 +75,6 @@ variable.forEach((testVariable) => { idToken, }); - // console.log(coreKitInstance.tKey.metadata) - // console.log(coreKitInstance.state); // get key details await checkLogin(coreKitInstance); diff --git a/tests/setup.ts b/tests/setup.ts index 86a9c1bc..f6e6866f 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -106,8 +106,6 @@ export const newCoreKitLogInInstance = async ({ legacyFlag?: boolean; }) => { const localTsslib = tssLib ?? tssLibDKLS; - // console.log("localTssLib", localTsslib) - const instance = new Web3AuthMPCCoreKit({ web3AuthClientId: "torus-key-test", @@ -124,7 +122,6 @@ export const newCoreKitLogInInstance = async ({ const { idToken, parsedToken } = login ? await login(email) : await mockLogin(email); await instance.init(); - // console.log("legacy Flag", legacyFlag) if (mockStorageLayer) { instance.tKey.storageLayer = mockStorageLayer } From 5bac894231e523ae9ce3a202bae81ea9978ceba2 Mon Sep 17 00:00:00 2001 From: ieow Date: Fri, 28 Feb 2025 02:52:29 +0800 Subject: [PATCH 15/16] fix: rename signECDSA function name fix multicurve test to use new storage instance fix useClientGeneratedTSSKey bug --- src/interfaces.ts | 2 +- src/mpcCoreKit.ts | 16 ++++++++-------- src/utils.ts | 2 +- tests/backwardCompatible.spec.ts | 2 +- tests/login.spec.ts | 10 +++++----- tests/multiCurveTest.spec.ts | 5 ++--- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/interfaces.ts b/src/interfaces.ts index 1850a871..2b1173bd 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -486,7 +486,7 @@ export interface ICoreKit { * - hashed: The data is already hashed. Do not hash again. Only works for ecdsa-secp256k1. * - secp256k1Precompute: Provide a precomputed client for faster signing. Only works for ecdsa-secp256k1. */ - signECDSA( + sign_ECDSA_secp256k1( data: Buffer, opts?: { hashed?: boolean; diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 6ad5d659..088a497c 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -890,7 +890,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { }; } - public async signECDSA(data: Uint8Array, opts?: { hashed?: boolean; secp256k1Precompute?: Secp256k1PrecomputedClient }) { + public async sign_ECDSA_secp256k1(data: Uint8Array, opts?: { hashed?: boolean; secp256k1Precompute?: Secp256k1PrecomputedClient }) { if (!this.supportedCurveKeyTypes.has(KeyType.secp256k1)) { throw CoreKitError.default(`secp256k1 KeyTYpe is not supported, please configure secp256k1 curve key type `); } @@ -899,8 +899,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } const { hashed = false, secp256k1Precompute } = opts || {}; - // TODO: replace buffer to uint8array - const sig = await this.sign_ECDSA_secp256k1(Buffer.from(data), hashed, secp256k1Precompute); + const sig = await this._sign_ECDSA_secp256k1(Buffer.from(data), hashed, secp256k1Precompute); return Buffer.concat([sig.r, sig.s, Buffer.from([sig.v])]); } @@ -946,7 +945,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { } // mutation function - async deleteFactor(factorPub: Point, factorKey?: BNString): Promise { if (!this.state.factorKey) { throw CoreKitError.factorKeyNotPresent("factorKey not present in state when deleting a factor."); @@ -1177,9 +1175,11 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { if (keyType === KeyType.ed25519) { const k = generateEd25519Seed(); importKey.ed25519 = k.toString("hex"); - } else if (keyType === KeyType.secp256k1 && !!this.options.useClientGeneratedTSSKey) { - const k = secp256k1.genKeyPair().getPrivate(); - importKey.secp256k1 = scalarBNToBufferSEC1(k).toString("hex"); + } else if (keyType === KeyType.secp256k1) { + if (this.options.useClientGeneratedTSSKey) { + const k = secp256k1.genKeyPair().getPrivate(); + importKey.secp256k1 = scalarBNToBufferSEC1(k).toString("hex"); + } } else { throw CoreKitError.default(`Unsupported key type and sig type combination `); } @@ -1648,7 +1648,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit, IMPCContext { return this.tkey.computeAccountNonce(this.state.accountIndex); } - private async sign_ECDSA_secp256k1(data: Buffer, hashed: boolean = false, precomputedTssClient?: Secp256k1PrecomputedClient) { + private async _sign_ECDSA_secp256k1(data: Buffer, hashed: boolean = false, precomputedTssClient?: Secp256k1PrecomputedClient) { const executeSign = async (client: Client, serverCoeffs: Record, hashedData: Buffer, signatures: string[]) => { const { r, s, recoveryParam } = await client.sign(hashedData.toString("base64"), true, "", "keccak256", { signatures, diff --git a/src/utils.ts b/src/utils.ts index bf92fae8..ef1fbc5f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -202,7 +202,7 @@ export function makeEthereumSigner(kit: Web3AuthMPCCoreKit): EthereumSigner { } return { sign: async (msgHash: Buffer) => { - const sig = await kit.signECDSA(msgHash, { hashed: true }); + const sig = await kit.sign_ECDSA_secp256k1(msgHash, { hashed: true }); return sigToRSV(sig); }, getPublic: async () => { diff --git a/tests/backwardCompatible.spec.ts b/tests/backwardCompatible.spec.ts index 2bfe3eec..d0443956 100644 --- a/tests/backwardCompatible.spec.ts +++ b/tests/backwardCompatible.spec.ts @@ -122,7 +122,7 @@ variable.forEach((testVariable) => { const msg = "hello world"; const msgBuffer = Buffer.from(msg); const msgHash = keccak256(msgBuffer); - const signature = sigToRSV(await coreKitInstance.signECDSA(msgHash, { hashed: true } )); + const signature = sigToRSV(await coreKitInstance.sign_ECDSA_secp256k1(msgHash, { hashed: true } )); const secp256k1 = new EC("secp256k1"); const pubkey = secp256k1.recoverPubKey(msgHash, signature, signature.v) as EllipticPoint; diff --git a/tests/login.spec.ts b/tests/login.spec.ts index 7489fbb7..69378cb4 100644 --- a/tests/login.spec.ts +++ b/tests/login.spec.ts @@ -156,13 +156,13 @@ variable.forEach((testVariable) => { const secp256k1 = new EC("secp256k1"); // Sign hash. - const signature = sigToRSV(await coreKitInstance.signECDSA(msgHash, { hashed: true })); + const signature = sigToRSV(await coreKitInstance.sign_ECDSA_secp256k1(msgHash, { hashed: true })); const pubkey = secp256k1.recoverPubKey(msgHash, signature, signature.v) as EllipticPoint; const publicKeyPoint = bufferToElliptic(coreKitInstance.getPubKey(keyType)); assert(pubkey.eq(publicKeyPoint)); // Sign full message. - const signature2 = sigToRSV(await coreKitInstance.signECDSA(msgBuffer)); + const signature2 = sigToRSV(await coreKitInstance.sign_ECDSA_secp256k1(msgBuffer)); const pubkey2 = secp256k1.recoverPubKey(msgHash, signature2, signature2.v) as EllipticPoint; assert(pubkey2.eq(publicKeyPoint)); }); @@ -186,7 +186,7 @@ variable.forEach((testVariable) => { const msg = "hello world 1"; const msgBuffer = Buffer.from(msg); const msgHash = keccak256(msgBuffer); - const signature1 = sigToRSV(await coreKitInstance.signECDSA(msgHash, { hashed: true })); + const signature1 = sigToRSV(await coreKitInstance.sign_ECDSA_secp256k1(msgHash, { hashed: true })); const pubkeyIndex0 = secp256k1.recoverPubKey(msgHash, signature1, signature1.v); const publicKeyPoint0 = bufferToElliptic(coreKitInstance.getPubKey(keyType)); @@ -198,7 +198,7 @@ variable.forEach((testVariable) => { const msgBuffer1 = Buffer.from(msg1); const msgHash1 = keccak256(msgBuffer1); - const signature2 = sigToRSV(await coreKitInstance.signECDSA(msgHash1, { hashed: true })); + const signature2 = sigToRSV(await coreKitInstance.sign_ECDSA_secp256k1(msgHash1, { hashed: true })); const pubkeyIndex1 = secp256k1.recoverPubKey(msgHash1, signature2, signature2.v) as EllipticPoint; const publicKeyPoint1 = bufferToElliptic(coreKitInstance.getPubKey(keyType)); @@ -211,7 +211,7 @@ variable.forEach((testVariable) => { const msg2 = "hello world 3"; const msgBuffer2 = Buffer.from(msg2); const msgHash2 = keccak256(msgBuffer2); - const signature3 = sigToRSV(await coreKitInstance.signECDSA(msgHash2, { hashed: true })); + const signature3 = sigToRSV(await coreKitInstance.sign_ECDSA_secp256k1(msgHash2, { hashed: true })); const pubkeyIndex2 = secp256k1.recoverPubKey(msgHash2, signature3, signature3.v) as EllipticPoint; const publicKeyPoint2 = bufferToElliptic(coreKitInstance.getPubKey(keyType)); diff --git a/tests/multiCurveTest.spec.ts b/tests/multiCurveTest.spec.ts index 4a1893b4..a987382e 100644 --- a/tests/multiCurveTest.spec.ts +++ b/tests/multiCurveTest.spec.ts @@ -20,7 +20,6 @@ import { schnorr as bip340 } from '@noble/curves/secp256k1'; const web3AuthNetwork = WEB3AUTH_NETWORK.DEVNET; const manualSync = false; -const storageInstance = new MemoryStorage(); const verifierId = "multicurvetest" const mockSL = new MockStorageLayer({ @@ -36,7 +35,7 @@ describe("multiCurveTest", () => { baseUrl: "http://localhost:3000", uxMode: "nodejs", supportedKeyTypes: [KeyType.secp256k1, KeyType.ed25519], - storage: storageInstance, + storage: new MemoryStorage(), manualSync, }); @@ -46,7 +45,7 @@ describe("multiCurveTest", () => { const hash = keccak_256(message); instance.addTssLibs([dklslib]); - const result = await instance.signECDSA(Buffer.from(hash), {hashed: true}) + const result = await instance.sign_ECDSA_secp256k1(Buffer.from(hash), {hashed: true}) const {r, s } = sigToRSV(result); const validsecp256k1 = secp256k1.verify({ From 92340a73ef7c23654cdb03324cbec430845ac804 Mon Sep 17 00:00:00 2001 From: ieow Date: Wed, 12 Mar 2025 17:22:31 +0800 Subject: [PATCH 16/16] fix: update demo app --- demo/redirect-flow-example/package-lock.json | 22 +-- demo/redirect-flow-example/package.json | 4 +- demo/redirect-flow-example/src/App.tsx | 171 ++++++++++--------- package-lock.json | 4 +- src/mpcCoreKit.ts | 35 ++-- 5 files changed, 124 insertions(+), 112 deletions(-) diff --git a/demo/redirect-flow-example/package-lock.json b/demo/redirect-flow-example/package-lock.json index ed42060a..817aa920 100644 --- a/demo/redirect-flow-example/package-lock.json +++ b/demo/redirect-flow-example/package-lock.json @@ -8,7 +8,7 @@ "name": "redirect-flow-example", "version": "0.1.0", "dependencies": { - "@tkey/common-types": "^15.1.0", + "@tkey/common-types": "^15.2.1-alpha.0", "@toruslabs/torus.js": "15.2.0-alpha.0", "@toruslabs/tss-dkls-lib": "^5.0.0-alpha.0", "@toruslabs/tss-frost-lib": "^2.0.0-alpha.0", @@ -21,7 +21,7 @@ "@web3auth/base": "^9.0.2", "@web3auth/ethereum-mpc-provider": "^9.3.0", "@web3auth/mpc-core-kit": "file:../..", - "@web3auth/mpc-passkey-plugin": "0.1.15-alpha.0", + "@web3auth/mpc-passkey-plugin": "~0.1.15-alpha.0", "browserify-zlib": "^0.2.0", "copy-webpack-plugin": "^11.0.0", "html-webpack-plugin": "^5.5.3", @@ -57,14 +57,14 @@ }, "../..": { "name": "@web3auth/mpc-core-kit", - "version": "4.1.6-alpha.0", + "version": "4.1.7-alpha.0", "license": "ISC", "dependencies": { - "@tkey/common-types": "^15.1.0", - "@tkey/core": "^15.1.0", + "@tkey/common-types": "file:../tkey/packages/common-types", + "@tkey/core": "file:../tkey/packages/core/tkey-core-15.2.1-alpha.0.tgz", "@tkey/share-serialization": "^15.1.0", - "@tkey/storage-layer-torus": "^15.1.0", - "@tkey/tss": "^15.1.0", + "@tkey/storage-layer-torus": "file:../tkey/packages/storage-layer-torus/tkey-storage-layer-torus-15.2.1-alpha.0.tgz", + "@tkey/tss": "file:../tkey/packages/tss/tkey-tss-15.2.1-alpha.0.tgz", "@toruslabs/constants": "^14.2.0", "@toruslabs/customauth": "^20.3.0", "@toruslabs/elliptic-wrapper": "^0.1.1", @@ -73,7 +73,7 @@ "@toruslabs/metadata-helpers": "^6.0.0", "@toruslabs/openlogin-utils": "^8.2.1", "@toruslabs/session-manager": "^3.1.0", - "@toruslabs/torus.js": "15.2.0-alpha.0", + "@toruslabs/torus.js": "file:../torus.js/toruslabs-torus.js-15.1.1.tgz", "@toruslabs/tss-client": "^3.3.0-alpha.0", "@toruslabs/tss-frost-client": "^1.0.1-alpha.0", "@toruslabs/tss-frost-common": "^1.0.2-alpha.0", @@ -976,9 +976,9 @@ "license": "MIT" }, "node_modules/@tkey/common-types": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@tkey/common-types/-/common-types-15.1.0.tgz", - "integrity": "sha512-oA5gLoyhNNMgCKcjvwLyU31TVS5KMT+lotRrjjoBdDvS0keZwzSLrtHWbXj8jZDlSZaqbd3VlPbCoHcqpk1irA==", + "version": "15.2.1-alpha.0", + "resolved": "https://registry.npmjs.org/@tkey/common-types/-/common-types-15.2.1-alpha.0.tgz", + "integrity": "sha512-0BXtkB2PHNtV+fCmTVhWRqz/0tc975/z2onqCDQyCn0Lk36uhAPbEwCPRJ4vrccICxVizuYagZ+CazaEjk/ICA==", "license": "MIT", "dependencies": { "@toruslabs/customauth": "^20.3.0", diff --git a/demo/redirect-flow-example/package.json b/demo/redirect-flow-example/package.json index 098bf77b..b8133dbb 100644 --- a/demo/redirect-flow-example/package.json +++ b/demo/redirect-flow-example/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { - "@tkey/common-types": "^15.1.0", + "@tkey/common-types": "^15.2.1-alpha.0", "@toruslabs/torus.js": "15.2.0-alpha.0", "@toruslabs/tss-dkls-lib": "^5.0.0-alpha.0", "@toruslabs/tss-frost-lib": "^2.0.0-alpha.0", @@ -16,7 +16,7 @@ "@web3auth/base": "^9.0.2", "@web3auth/ethereum-mpc-provider": "^9.3.0", "@web3auth/mpc-core-kit": "file:../..", - "@web3auth/mpc-passkey-plugin": "0.1.15-alpha.0", + "@web3auth/mpc-passkey-plugin": "~0.1.15-alpha.0", "browserify-zlib": "^0.2.0", "copy-webpack-plugin": "^11.0.0", "html-webpack-plugin": "^5.5.3", diff --git a/demo/redirect-flow-example/src/App.tsx b/demo/redirect-flow-example/src/App.tsx index e6a6fb11..e3d57479 100644 --- a/demo/redirect-flow-example/src/App.tsx +++ b/demo/redirect-flow-example/src/App.tsx @@ -104,7 +104,7 @@ function App() { uxMode: "redirect", manualSync: true, storage: window.localStorage, - tssLib: selectedTssLib, + supportedKeyTypes: [KeyType.secp256k1, KeyType.ed25519], useDKG: false, }) ); @@ -118,7 +118,7 @@ function App() { // ) ) async function setupProvider(chainConfig?: CustomChainConfig) { - if (coreKitInstance.current.keyType !== KeyType.secp256k1) { + if (!coreKitInstance.current.getSupportedCurveKeyTypes().includes(KeyType.ed25519)) { console.warn(`Ethereum requires keytype ${KeyType.secp256k1}, skipping provider setup`); return; } @@ -175,7 +175,7 @@ function App() { uxMode: "redirect", manualSync: false, storage: window.localStorage, - tssLib: selectedTssLib, + supportedKeyTypes: [KeyType.ed25519, KeyType.secp256k1], useDKG: false, }) @@ -205,14 +205,11 @@ function App() { if (!coreKitInstance) { throw new Error("coreKitInstance not found"); } - const factorPubs = coreKitInstance.current.tKey.metadata.factorPubs; - if (!factorPubs) { + const factorPubs = coreKitInstance.current.getTssFactorPub(); + if (!factorPubs || factorPubs.length === 0) { throw new Error("factorPubs not found"); } - const pubsHex = factorPubs[coreKitInstance.current.tKey.tssTag].map(pub => { - return pub.toSEC1(factorKeyCurve, true).toString("hex"); - }); - uiConsole(pubsHex); + uiConsole(factorPubs); }; const loginWithMock = async () => { @@ -406,64 +403,85 @@ function App() { return balance; }; - const signMessage = async (): Promise => { - if (coreKitInstance.current.sigType === SIG_TYPE.ECDSA_SECP256K1) { - if (!web3) { - uiConsole("web3 not initialized yet"); - return; - } - const fromAddress = (await web3.eth.getAccounts())[0]; - const message = "hello"; - const signedMessage = await web3.eth.personal.sign(message, fromAddress, ""); - - uiConsole(signedMessage); - } else if (coreKitInstance.current.sigType === SIG_TYPE.ED25519 || coreKitInstance.current.sigType === SIG_TYPE.BIP340) { - const msg = Buffer.from("hello signer!"); - const sig = await coreKitInstance.current.sign(msg); - uiConsole(sig.toString("hex")); + const signMessageEd25519 = async (): Promise => { + + if (!coreKitInstance.current.getSupportedSigTypes().includes(SIG_TYPE.ED25519)) { + coreKitInstance.current.addTssLibs([tssLibFrost]); + } + const msg = Buffer.from("hello signer!"); + const sig = await coreKitInstance.current.signED25519(msg); + uiConsole(sig.toString("hex")); + } + + const signMessage = async (): Promise => { + if (!web3) { + uiConsole("web3 not initialized yet"); + return; } + if (!coreKitInstance.current.getSupportedSigTypes().includes(SIG_TYPE.ECDSA_SECP256K1)) { + coreKitInstance.current.addTssLibs([tssLibDkls]); + } + const fromAddress = (await web3.eth.getAccounts())[0]; + const message = "hello"; + const signedMessage = await web3.eth.personal.sign(message, fromAddress, ""); + uiConsole(signedMessage); }; const signWithKeyTweak = async (): Promise => { - if (coreKitInstance.current.sigType === SIG_TYPE.ECDSA_SECP256K1) { - throw new Error("Not supported for this signature type"); - } else if (coreKitInstance.current.sigType === SIG_TYPE.ED25519 || coreKitInstance.current.sigType === SIG_TYPE.BIP340) { - const msg = Buffer.from("hello signer!"); - const keyTweak = (() => { - const ec = new EC(coreKitInstance.current.keyType); - return ec.genKeyPair().getPrivate(); - })(); - const sig = await coreKitInstance.current.sign(msg, { keyTweak }); - uiConsole(sig.toString("hex")); + if (!coreKitInstance.current.getSupportedCurveKeyTypes().includes(KeyType.secp256k1) ) { + throw new Error("Not supported for this curve type"); } + + if (!coreKitInstance.current.getSupportedSigTypes().includes(SIG_TYPE.BIP340)) { + coreKitInstance.current.addTssLibs([tssLibFrostBip340]) + } + + const msg = Buffer.from("hello signer!"); + const keyTweak = (() => { + const ec = new EC(KeyType.secp256k1); + return ec.genKeyPair().getPrivate(); + })(); + const sig = await coreKitInstance.current.signBIP340(msg ); + uiConsole(sig.toString("hex")); }; const signMessageWithPrecomputedTss = async (): Promise => { - if (coreKitInstance.current.keyType === "secp256k1") { - const precomputedTssClient = await coreKitInstance.current.precompute_secp256k1(); - const msg = Buffer.from("hello signer!"); - const sig = await coreKitInstance.current.sign(msg, { secp256k1Precompute: precomputedTssClient }); - uiConsole(sig.toString("hex")); - } else { - throw new Error("Not supported for this key type"); + + if (!coreKitInstance.current.getSupportedCurveKeyTypes().includes(KeyType.secp256k1) ) { + throw new Error("Not supported for this curve type"); } + if (!coreKitInstance.current.getSupportedSigTypes().includes(SIG_TYPE.ECDSA_SECP256K1)) { + coreKitInstance.current.addTssLibs([tssLibDkls]) + } + + const precomputedTssClient = await coreKitInstance.current.precompute_secp256k1(); + const msg = Buffer.from("hello signer!"); + const sig = await coreKitInstance.current.sign_ECDSA_secp256k1(msg, { secp256k1Precompute: precomputedTssClient }); + uiConsole(sig.toString("hex")); }; const signMultipleMessagesWithPrecomputedTss = async (): Promise => { - if (coreKitInstance.current.keyType === "secp256k1") { - const [precomputedTssClient, precomputedTssClient2] = await Promise.all([coreKitInstance.current.precompute_secp256k1(), coreKitInstance.current.precompute_secp256k1()]); - const msg = Buffer.from("hello signer!"); - const sig = await coreKitInstance.current.sign(msg, { secp256k1Precompute: precomputedTssClient }); - const msg2 = Buffer.from("hello signer2!"); - - const sig2 = await coreKitInstance.current.sign(msg2, { secp256k1Precompute: precomputedTssClient2 }); - uiConsole("Sig1: ", sig.toString("hex"), "Sig2: ", sig2.toString("hex")); - } else { - throw new Error("Not supported for this key type"); + if (!coreKitInstance.current.getSupportedCurveKeyTypes().includes(KeyType.secp256k1) ) { + throw new Error("Not supported for this curve type"); + } + if (!coreKitInstance.current.getSupportedSigTypes().includes(SIG_TYPE.ECDSA_SECP256K1)) { + coreKitInstance.current.addTssLibs([tssLibDkls]) } + + const [precomputedTssClient, precomputedTssClient2] = await Promise.all([coreKitInstance.current.precompute_secp256k1(), coreKitInstance.current.precompute_secp256k1()]); + + const msg = Buffer.from("hello signer!"); + const sig = await coreKitInstance.current.sign_ECDSA_secp256k1(msg, { secp256k1Precompute: precomputedTssClient }); + const msg2 = Buffer.from("hello signer2!"); + + const sig2 = await coreKitInstance.current.sign_ECDSA_secp256k1(msg2, { secp256k1Precompute: precomputedTssClient2 }); + uiConsole("Sig1: ", sig.toString("hex"), "Sig2: ", sig2.toString("hex")); + }; + + const switchChainSepolia = async () => { if (!provider) { uiConsole("provider not initialized yet"); @@ -705,32 +723,6 @@ function App() { await coreKitInstance.current.commitChanges(); }; - const tssLibSelector = ( -
- - -
- ); - const loggedInView = ( <>

Account Details

@@ -739,8 +731,12 @@ function App() { Get User Info - + + - + + + + @@ -872,6 +876,10 @@ function App() { Get Balance + + @@ -909,7 +917,6 @@ function App() { const unloggedInView = ( <> - {tssLibSelector} setMockEmail(e.target.value)}>