diff --git a/package-lock.json b/package-lock.json index e16d226ba..3a27834a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2058,6 +2058,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } @@ -2075,6 +2076,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -2092,6 +2094,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -2109,6 +2112,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -2126,6 +2130,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -2143,6 +2148,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -2160,6 +2166,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -2177,6 +2184,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -2194,6 +2202,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -2211,6 +2220,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -2228,6 +2238,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -2245,6 +2256,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -2262,6 +2274,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -2279,6 +2292,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -2296,6 +2310,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -2313,6 +2328,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -2330,6 +2346,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -2347,6 +2364,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -2364,6 +2382,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -2381,6 +2400,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -2398,6 +2418,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } @@ -2415,6 +2436,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -2432,6 +2454,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -2449,6 +2472,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -5290,7 +5314,6 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/@toruslabs/eccrypto/-/eccrypto-5.0.4.tgz", "integrity": "sha512-5PrSe2sn5Ed0u/2oRFtKaGOYpXJS+rJQXlYqxzy7Tbe2wLPCJh5/hZ3yStLfZmrYjHlWYwUx3AIpL/pUOOSU4w==", - "license": "CC0-1.0", "dependencies": { "elliptic": "^6.5.5" }, @@ -10185,6 +10208,18 @@ "@esbuild/win32-x64": "0.23.0" } }, + "node_modules/esbuild-register": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", + "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, "node_modules/escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", @@ -25669,16 +25704,16 @@ "version": "15.1.0", "license": "MIT", "dependencies": { + "@noble/curves": "^1.6.0", "@toruslabs/customauth": "^20.3.0", - "@toruslabs/eccrypto": "^5.0.4", + "@toruslabs/eccrypto": "^6.0.0-0", "@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" + "@types/elliptic": "^6.4.18", + "esbuild-register": "^3.6.0" }, "engines": { "node": ">=18.x", @@ -25688,6 +25723,43 @@ "@babel/runtime": "7.x" } }, + "packages/common-types/node_modules/@noble/curves": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz", + "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==", + "dependencies": { + "@noble/hashes": "1.5.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "packages/common-types/node_modules/@noble/hashes": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", + "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "packages/common-types/node_modules/@toruslabs/eccrypto": { + "version": "6.0.0-0", + "resolved": "https://registry.npmjs.org/@toruslabs/eccrypto/-/eccrypto-6.0.0-0.tgz", + "integrity": "sha512-GTVsxMsD11mGUYSmrGnR2ItU2oMhu/mgVR/f7Sgq4I2gFecKf9ltHuha3M5kH8rVqFrtaupaZPxNXBLZEF3tcw==", + "dependencies": { + "@noble/curves": "^1.6.0" + }, + "engines": { + "node": ">=18.x", + "npm": ">=9.x" + } + }, "packages/core": { "name": "@tkey/core", "version": "15.1.0", @@ -25922,7 +25994,8 @@ }, "devDependencies": { "@types/bn.js": "^5.1.5", - "@types/json-stable-stringify": "^1.0.36" + "@types/json-stable-stringify": "^1.0.36", + "esbuild-register": "^3.6.0" }, "engines": { "node": ">=18.x", diff --git a/packages/common-types/package.json b/packages/common-types/package.json index 3d0c536a7..995e47560 100644 --- a/packages/common-types/package.json +++ b/packages/common-types/package.json @@ -22,7 +22,7 @@ "url": "git+https://github.com/tkey/tkey.git" }, "scripts": { - "test": "cross-env MOCKED=true mocha --config ../../.mocharc.json ", + "test": "cross-env MOCKED=true node --test -r esbuild-register test/*.ts", "coverage": "nyc npm test", "coverage-production": "nyc npm run test-production", "test-development": "cross-env MOCKED=false METADATA=http://localhost:5051 mocha --config ../../.mocharc.json ", @@ -43,16 +43,16 @@ "@babel/runtime": "7.x" }, "dependencies": { + "@noble/curves": "^1.6.0", "@toruslabs/customauth": "^20.3.0", - "@toruslabs/eccrypto": "^5.0.4", + "@toruslabs/eccrypto": "^6.0.0-0", "@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" + "@types/elliptic": "^6.4.18", + "esbuild-register": "^3.6.0" }, "bugs": { "url": "https://github.com/tkey/tkey/issues" diff --git a/packages/common-types/src/base/BNUtils.ts b/packages/common-types/src/base/BNUtils.ts deleted file mode 100644 index 188ef06c0..000000000 --- a/packages/common-types/src/base/BNUtils.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { getPublic } from "@toruslabs/eccrypto"; -import BN from "bn.js"; -import type { curve, ec } from "elliptic"; - -import { BNString } from "../baseTypes/commonTypes"; -import { secp256k1 } from "../utils"; -import Point from "./Point"; - -// These functions are here because BN can't be extended -export const toPrivKeyEC = (bn: BN): ec.KeyPair => secp256k1.keyFromPrivate(bn.toString("hex", 64)); - -export const toPrivKeyECC = (bn: BNString): Buffer => { - const tmp = new BN(bn, "hex"); - return Buffer.from(tmp.toString("hex", 64), "hex"); -}; - -export const getPubKeyEC = (bn: BN): curve.base.BasePoint => secp256k1.keyFromPrivate(bn.toString("hex", 64)).getPublic(); - -export const getPubKeyECC = (bn: BN): Buffer => getPublic(toPrivKeyECC(bn)); - -export const getPubKeyPoint = (bn: BN): Point => { - const pubKeyEc = getPubKeyEC(bn); - return new Point(pubKeyEc.getX().toString("hex"), pubKeyEc.getY().toString("hex")); -}; diff --git a/packages/common-types/src/base/Point.ts b/packages/common-types/src/base/Point.ts index ccb8d88a2..f8d3417ca 100644 --- a/packages/common-types/src/base/Point.ts +++ b/packages/common-types/src/base/Point.ts @@ -1,85 +1,71 @@ -import BN from "bn.js"; +import { Hex, hexToNumber } from "@noble/curves/abstract/utils"; +import { ed25519 } from "@noble/curves/ed25519"; +import { secp256k1 } from "@noble/curves/secp256k1"; -import { BNString, EllipticCurve, EllipticPoint, IPoint, StringifiedType } from "../baseTypes/commonTypes"; -import { secp256k1 } from "../utils"; +import { IPoint, StringifiedType } from "../baseTypes/commonTypes"; +import { strip0x } from "../utils"; -class Point implements IPoint { - x: BN | null; +export enum curveType { + "secp256k1" = "secp256k1", + "ed25519" = "ed25519", +} - y: BN | null; +export class PointBigInt { + x: bigint; - constructor(x: BNString, y: BNString) { - this.x = new BN(x, "hex"); - this.y = new BN(y, "hex"); - } + y: bigint; - static fromScalar(s: BN, ec: EllipticCurve): Point { - const p = (ec.g as EllipticPoint).mul(s); - return Point.fromElliptic(p); + constructor(x: bigint, y: bigint) { + this.x = x; + this.y = y; } +} - /** - * @deprecated Use `fromSEC1` instead. - */ - static fromCompressedPub(value: string): Point { - const key = secp256k1.keyFromPublic(value, "hex"); - const pt = key.getPublic(); - return new Point(pt.getX(), pt.getY()); - } +class Point implements IPoint { + x: bigint | null; - static fromJSON(value: StringifiedType): Point { - const { x, y } = value; - return new Point(x, y); + y: bigint | null; + + constructor(x: bigint, y: bigint) { + this.x = x; + this.y = y; } - static fromElliptic(p: EllipticPoint): Point { - if (p.isInfinity()) { - return new Point(null, null); + static fromScalar(curve: curveType, s: Hex): Point { + if (curve === "secp256k1") { + const point = secp256k1.ProjectivePoint.fromPrivateKey(s); + return new Point(point.x, point.y); } - return new Point(p.getX(), p.getY()); - } - /** - * Construct a point from SEC1 format. - */ - static fromSEC1(ec: EllipticCurve, encodedPoint: string): Point { - // "elliptic"@6.5.4 can't decode identity. - if (encodedPoint.length === 2 && encodedPoint === "00") { - const identity = (ec.g as EllipticPoint).mul(new BN(0)); - return Point.fromElliptic(identity); + if (curve === "ed25519") { + const point = ed25519.ExtendedPoint.fromPrivateKey(s); + return new Point(point.x, point.y); } - const key = ec.keyFromPublic(encodedPoint, "hex"); - const pt = key.getPublic(); - return Point.fromElliptic(pt); + throw new Error("curve not supported"); + } + + static fromJSON(value: StringifiedType): Point { + const { x, y } = value; + return new Point(hexToNumber(x), hexToNumber(y)); } /** - * @deprecated Use `toSEC1` instead. - * - * complies with EC and elliptic pub key types + * Construct a point from SEC1 format. */ - encode(enc: string): Buffer { - switch (enc) { - case "arr": - return Buffer.concat([Buffer.from("0x04", "hex"), Buffer.from(this.x.toString("hex"), "hex"), Buffer.from(this.y.toString("hex"), "hex")]); - case "elliptic-compressed": { - const ec = secp256k1; - const key = ec.keyFromPublic({ x: this.x.toString("hex"), y: this.y.toString("hex") }, "hex"); - return Buffer.from(key.getPublic(true, "hex")); - } - default: - throw new Error("encoding doesnt exist in Point"); + static fromSEC1(curve: curveType, encodedPoint: string): Point { + const encodedHex = strip0x(encodedPoint); + if (curve === "secp256k1") { + const point = secp256k1.ProjectivePoint.fromHex(encodedHex); + return new Point(point.x, point.y); } - } - toEllipticPoint(ec: EllipticCurve): EllipticPoint { - if (this.isIdentity()) { - return (ec.g as EllipticPoint).mul(new BN(0)); + if (curve === "ed25519") { + const point = ed25519.ExtendedPoint.fromHex(encodedHex); + return new Point(point.x, point.y); } - const keyPair = ec.keyFromPublic({ x: this.x.toString("hex"), y: this.y.toString("hex") }, "hex"); - return keyPair.getPublic(); + throw new Error("unknown curve type"); } /** @@ -88,20 +74,22 @@ class Point implements IPoint { * @param compressed - Whether to use compressed format. * @returns The SEC1-encoded point. */ - toSEC1(ec: EllipticCurve, compressed = false): Buffer { - // "elliptic"@6.5.4 can't encode identity. - if (this.isIdentity()) { - return Buffer.from("00", "hex"); + toSEC1(ec: curveType, compressed = false): Uint8Array { + if (ec === "secp256k1") { + const point = secp256k1.ProjectivePoint.fromAffine({ x: this.x, y: this.y }); + return point.toRawBytes(compressed); } - const p = this.toEllipticPoint(ec); - return Buffer.from(p.encode("hex", compressed), "hex"); + if (ec === "ed25519") { + const point = ed25519.ExtendedPoint.fromAffine({ x: this.x, y: this.y }); + return point.toRawBytes(compressed); + } } toJSON(): StringifiedType { return { - x: this.x.toString("hex"), - y: this.y.toString("hex"), + x: this.x.toString(16), + y: this.y.toString(16), }; } @@ -110,10 +98,10 @@ class Point implements IPoint { } equals(p: Point): boolean { - if (this.isIdentity()) { - return p.isIdentity(); - } - return this.x.eq(p.x) && this.y.eq(p.y); + // if (this.isIdentity()) { + // return p.isIdentity(); + // } + return this.x === p.x && this.y === p.y; } } diff --git a/packages/common-types/src/base/Polynomial.ts b/packages/common-types/src/base/Polynomial.ts index 0b83b69ea..21ec657ab 100644 --- a/packages/common-types/src/base/Polynomial.ts +++ b/packages/common-types/src/base/Polynomial.ts @@ -1,67 +1,55 @@ -import BN from "bn.js"; +import { secp256k1 } from "@noble/curves/secp256k1"; -import { BNString, ISerializable, PolynomialID, StringifiedType } from "../baseTypes/commonTypes"; -import { secp256k1 } from "../utils"; -import { getPubKeyPoint } from "./BNUtils"; -import Point from "./Point"; +import { ISerializable, PolynomialID, StringifiedType } from "../baseTypes/commonTypes"; +import { bigIntToHex, bigIntUmod } from "../utils"; +import Point, { curveType } from "./Point"; import PublicPolynomial from "./PublicPolynomial"; import Share from "./Share"; - // @flow export type ShareMap = { [x: string]: Share; }; class Polynomial implements ISerializable { - polynomial: BN[]; + polynomial: bigint[]; publicPolynomial: PublicPolynomial; - constructor(polynomial: BN[]) { + constructor(polynomial: bigint[]) { this.polynomial = polynomial; } static fromJSON(value: StringifiedType): Polynomial { const { polynomial } = value; - return new Polynomial(polynomial.map((x: string) => new BN(x, "hex"))); + return new Polynomial(polynomial.map((x: string) => Point.fromSEC1(curveType.secp256k1, x))); } getThreshold(): number { return this.polynomial.length; } - polyEval(x: BNString): BN { - const tmpX = new BN(x, "hex"); - let xi = new BN(tmpX); - let sum = new BN(0); - sum = sum.add(this.polynomial[0]); + polyEval(x: bigint): bigint { + const tmpX = x; + let xi = x; + let sum = BigInt(0); + + sum = sum + this.polynomial[0]; for (let i = 1; i < this.polynomial.length; i += 1) { - const tmp = xi.mul(this.polynomial[i]); - sum = sum.add(tmp); - sum = sum.umod(secp256k1.curve.n); - xi = xi.mul(new BN(tmpX)); - xi = xi.umod(secp256k1.curve.n); + const tmp = xi * this.polynomial[i]; + sum = sum + tmp; + sum = bigIntUmod(sum, secp256k1.CURVE.n); + xi = xi * tmpX; + xi = bigIntUmod(xi, secp256k1.CURVE.n); } return sum; } - generateShares(shareIndexes: BNString[]): ShareMap { - const newShareIndexes = shareIndexes.map((index) => { - if (typeof index === "number") { - return new BN(index); - } - if (index instanceof BN) { - return index; - } - if (typeof index === "string") { - return new BN(index, "hex"); - } - return index; - }); + generateShares(shareIndexes: bigint[]): ShareMap { + const newShareIndexes = shareIndexes; const shares: ShareMap = {}; for (let x = 0; x < newShareIndexes.length; x += 1) { - shares[newShareIndexes[x].toString("hex")] = new Share(newShareIndexes[x], this.polyEval(newShareIndexes[x])); + shares[newShareIndexes[x].toString(16)] = new Share(newShareIndexes[x], this.polyEval(newShareIndexes[x])); } return shares; } @@ -69,7 +57,7 @@ class Polynomial implements ISerializable { getPublicPolynomial(): PublicPolynomial { const polynomialCommitments: Point[] = []; for (let i = 0; i < this.polynomial.length; i += 1) { - polynomialCommitments.push(getPubKeyPoint(this.polynomial[i])); + polynomialCommitments.push(Point.fromScalar(curveType.secp256k1, bigIntToHex(this.polynomial[i]))); } this.publicPolynomial = new PublicPolynomial(polynomialCommitments); return this.publicPolynomial; @@ -81,7 +69,7 @@ class Polynomial implements ISerializable { toJSON(): StringifiedType { return { - polynomial: this.polynomial.map((x) => x.toString("hex")), + polynomial: this.polynomial.map((x) => x.toString(16)), }; } } diff --git a/packages/common-types/src/base/PublicPolynomial.ts b/packages/common-types/src/base/PublicPolynomial.ts index 009c0c222..5ae03550d 100644 --- a/packages/common-types/src/base/PublicPolynomial.ts +++ b/packages/common-types/src/base/PublicPolynomial.ts @@ -1,5 +1,7 @@ +import { bytesToHex } from "@noble/curves/abstract/utils"; + import { ISerializable, PolynomialID, StringifiedType } from "../baseTypes/commonTypes"; -import Point from "./Point"; +import Point, { curveType } from "./Point"; class PublicPolynomial implements ISerializable { polynomialCommitments: Point[]; @@ -22,7 +24,7 @@ class PublicPolynomial implements ISerializable { getPolynomialID(): PolynomialID { let idSeed = ""; for (let i = 0; i < this.polynomialCommitments.length; i += 1) { - let nextChunk = this.polynomialCommitments[i].encode("elliptic-compressed").toString(); + let nextChunk = bytesToHex(this.polynomialCommitments[i].toSEC1(curveType.secp256k1, true)); if (i !== 0) { nextChunk = `|${nextChunk}`; } diff --git a/packages/common-types/src/base/PublicShare.ts b/packages/common-types/src/base/PublicShare.ts index 0e547545a..189cc7f8d 100644 --- a/packages/common-types/src/base/PublicShare.ts +++ b/packages/common-types/src/base/PublicShare.ts @@ -1,16 +1,14 @@ -import BN from "bn.js"; - -import { BNString, ISerializable, StringifiedType } from "../baseTypes/commonTypes"; +import { ISerializable, StringifiedType } from "../baseTypes/commonTypes"; import Point from "./Point"; class PublicShare implements ISerializable { shareCommitment: Point; - shareIndex: BN; + shareIndex: bigint; - constructor(shareIndex: BNString, shareCommitment: Point) { + constructor(shareIndex: bigint, shareCommitment: Point) { this.shareCommitment = new Point(shareCommitment.x, shareCommitment.y); - this.shareIndex = new BN(shareIndex, "hex"); + this.shareIndex = shareIndex; } static fromJSON(value: StringifiedType): PublicShare { @@ -21,7 +19,7 @@ class PublicShare implements ISerializable { toJSON(): StringifiedType { return { shareCommitment: this.shareCommitment, - shareIndex: this.shareIndex.toString("hex"), + shareIndex: this.shareIndex.toString(16), }; } } diff --git a/packages/common-types/src/base/Share.ts b/packages/common-types/src/base/Share.ts index 4e4e38fec..57bfc8384 100644 --- a/packages/common-types/src/base/Share.ts +++ b/packages/common-types/src/base/Share.ts @@ -1,32 +1,35 @@ -import BN from "bn.js"; - -import { BNString, ISerializable, StringifiedType } from "../baseTypes/commonTypes"; -import { getPubKeyPoint } from "./BNUtils"; +import { ISerializable, StringifiedType } from "../baseTypes/commonTypes"; +import { bigIntToHex, HexString, prefix0x } from "../utils"; +import Point, { curveType } from "./Point"; import PublicShare from "./PublicShare"; class Share implements ISerializable { - share: BN; + share: bigint; + + shareIndex: bigint; - shareIndex: BN; + constructor(shareIndex: bigint, share: bigint) { + this.share = share; + this.shareIndex = shareIndex; + } - constructor(shareIndex: BNString, share: BNString) { - this.share = new BN(share, "hex"); - this.shareIndex = new BN(shareIndex, "hex"); + static fromHex(shareIndex: HexString, share: HexString): Share { + return new Share(BigInt(shareIndex), BigInt(share)); } static fromJSON(value: StringifiedType): Share { const { share, shareIndex } = value; - return new Share(shareIndex, share); + return Share.fromHex(prefix0x(shareIndex), prefix0x(share)); } getPublicShare(): PublicShare { - return new PublicShare(this.shareIndex, getPubKeyPoint(this.share)); + return new PublicShare(this.shareIndex, Point.fromScalar(curveType.secp256k1, bigIntToHex(this.share))); } toJSON(): StringifiedType { return { - share: this.share.toString("hex"), - shareIndex: this.shareIndex.toString("hex"), + share: this.share.toString(16), + shareIndex: this.shareIndex.toString(16), }; } } diff --git a/packages/common-types/src/base/index.ts b/packages/common-types/src/base/index.ts index 861103b0d..b9f3573c0 100644 --- a/packages/common-types/src/base/index.ts +++ b/packages/common-types/src/base/index.ts @@ -1,4 +1,3 @@ -export * from "./BNUtils"; export * from "./Error"; export * from "./OneKey"; export { default as Point } from "./Point"; diff --git a/packages/common-types/src/baseTypes/aggregateTypes.ts b/packages/common-types/src/baseTypes/aggregateTypes.ts index e802e612e..be0aa8d1f 100644 --- a/packages/common-types/src/baseTypes/aggregateTypes.ts +++ b/packages/common-types/src/baseTypes/aggregateTypes.ts @@ -1,5 +1,4 @@ import type { CustomAuthArgs } from "@toruslabs/customauth"; -import BN from "bn.js"; import { Point, @@ -14,16 +13,8 @@ import { ShareStoreMap, ShareStorePolyIDShareIndexMap, } from "../base"; -import { - BNString, - EncryptedMessage, - ISerializable, - IServiceProvider, - IStorageLayer, - PolyIDAndShares, - PolynomialID, - ShareDescriptionMap, -} from "./commonTypes"; +import { HexString } from "../utils"; +import { EncryptedMessage, ISerializable, IServiceProvider, IStorageLayer, PolyIDAndShares, PolynomialID, ShareDescriptionMap } from "./commonTypes"; export interface IModule { moduleName: string; @@ -45,12 +36,12 @@ export type RefreshMiddlewareMap = { }; export type ReconstructKeyMiddlewareMap = { - [moduleName: string]: () => Promise; + [moduleName: string]: () => Promise; }; export type ShareSerializationMiddleware = { - serialize: (share: BN, type: string) => Promise; - deserialize: (serializedShare: unknown, type: string) => Promise; + serialize: (share: bigint, type: string) => Promise; + deserialize: (serializedShare: unknown, type: string) => Promise; }; export type FactorEncType = "direct" | "hierarchical"; @@ -97,7 +88,7 @@ export interface IMetadata extends ISerializable { setScopedStore(domain: string, data: unknown): void; getEncryptedShare(shareStore: ShareStore): Promise; getShareDescription(): ShareDescriptionMap; - shareToShareStore(share: BN): ShareStore; + shareToShareStore(share: bigint): ShareStore; addShareDescription(shareIndex: string, description: string): void; deleteShareDescription(shareIndex: string, description: string): void; updateShareDescription(shareIndex: string, oldDescription: string, newDescription: string): void; @@ -115,17 +106,17 @@ export interface IMetadata extends ISerializable { } export type InitializeNewKeyResult = { - secp256k1Key: BN; + secp256k1Key: bigint; ed25519Seed?: Buffer; deviceShare?: ShareStore; userShare?: ShareStore; }; export type ReconstructedKeyResult = { - secp256k1Key: BN; + secp256k1Key: bigint; ed25519Seed?: Buffer; - seedPhrase?: BN[]; - allKeys?: BN[]; + seedPhrase?: bigint[]; + allKeys?: bigint[]; }; export type MiddlewareExtraKeys = Omit; @@ -136,7 +127,7 @@ export type CatchupToLatestShareResult = { export type GenerateNewShareResult = { newShareStores: ShareStoreMap; - newShareIndex: BN; + newShareIndex: bigint; }; export type DeleteShareResult = { @@ -167,9 +158,9 @@ export type TKeyArgs = { }; export interface SecurityQuestionStoreArgs { - nonce: BNString; + nonce: HexString; - shareIndex: BNString; + shareIndex: HexString; sqPublicShare: PublicShare; @@ -187,7 +178,7 @@ export interface TkeyStoreArgs { } export interface ShareTransferStorePointerArgs { - pointer: BNString; + pointer: HexString; } export type BufferObj = { @@ -222,7 +213,7 @@ export type ISQAnswerStore = TkeyStoreItemType & { }; export type ISeedPhraseStoreWithKeys = ISeedPhraseStore & { - keys: BN[]; + keys: bigint[]; }; export type MetamaskSeedPhraseStore = ISeedPhraseStore & { @@ -230,27 +221,27 @@ export type MetamaskSeedPhraseStore = ISeedPhraseStore & { }; export type IPrivateKeyStore = TkeyStoreItemType & { - privateKey: BN; + privateKey: bigint; type: string; }; export interface ISeedPhraseFormat { type: string; validateSeedPhrase(seedPhrase: string): boolean; - deriveKeysFromSeedPhrase(seedPhraseStore: ISeedPhraseStore): Promise; + deriveKeysFromSeedPhrase(seedPhraseStore: ISeedPhraseStore): Promise; createSeedPhraseStore(seedPhrase?: string): Promise; } export interface IPrivateKeyFormat { - privateKey: BN; + privateKey: bigint; type: string; - validatePrivateKey(privateKey: BN): boolean; - createPrivateKeyStore(privateKey: BN): IPrivateKeyStore; + validatePrivateKey(privateKey: bigint): boolean; + createPrivateKeyStore(privateKey: bigint): IPrivateKeyStore; } export interface IAuthMetadata { metadata: IMetadata; - privKey?: BN; + privKey?: bigint; } export interface IMessageMetadata { @@ -261,14 +252,14 @@ export interface IMessageMetadata { export type IAuthMetadatas = IAuthMetadata[]; export type ShareStores = ShareStore[]; export type IMessageMetadatas = IMessageMetadata[]; -export type LocalTransitionShares = BN[]; +export type LocalTransitionShares = bigint[]; export type LocalTransitionData = (IAuthMetadata | IMessageMetadata | ShareStore)[]; export type LocalMetadataTransitions = [LocalTransitionShares, LocalTransitionData]; export interface ITKeyApi { getMetadata(): IMetadata; getStorageLayer(): IStorageLayer; - initialize(params: { input?: ShareStore; importKey?: BN; neverInitializeNewKey?: boolean }): Promise; + initialize(params: { input?: ShareStore; importKey?: bigint; neverInitializeNewKey?: boolean }): Promise; catchupToLatestShare(params: { shareStore: ShareStore; polyID?: string; @@ -282,17 +273,17 @@ export interface ITKeyApi { moduleName: string, middleware: (generalStore: unknown, oldShareStores: ShareStoreMap, newShareStores: ShareStoreMap) => unknown ): void; - _addReconstructKeyMiddleware(moduleName: string, middleware: () => Promise>): void; + _addReconstructKeyMiddleware(moduleName: string, middleware: () => Promise>): void; _addShareSerializationMiddleware( - serialize: (share: BN, type: string) => Promise, - deserialize: (serializedShare: unknown, type: string) => Promise + serialize: (share: bigint, type: string) => Promise, + deserialize: (serializedShare: unknown, type: string) => Promise ): void; generateNewShare(): Promise; - outputShareStore(shareIndex: BNString, polyID?: string): ShareStore; + outputShareStore(shareIndex: HexString, polyID?: string): ShareStore; inputShare(share: unknown, type?: string): Promise; - outputShare(shareIndex: BNString, type?: string): Promise; + outputShare(shareIndex: HexString, type?: string): Promise; inputShareStore(shareStore: ShareStore): void; - deleteShare(shareIndex: BNString): Promise; + deleteShare(shareIndex: HexString): Promise; encrypt(data: Buffer): Promise; decrypt(encryptedMesage: EncryptedMessage): Promise; @@ -311,7 +302,7 @@ export interface ITKey extends ITKeyApi, ISerializable { shares: ShareStorePolyIDShareIndexMap; - secp256k1Key: BN; + secp256k1Key: bigint; ed25519Key: Buffer; @@ -325,7 +316,7 @@ export interface ITKey extends ITKeyApi, ISerializable { _shareSerializationMiddleware: ShareSerializationMiddleware; - initialize(params: { input?: ShareStore; importKey?: BN; neverInitializeNewKey?: boolean }): Promise; + initialize(params: { input?: ShareStore; importKey?: bigint; neverInitializeNewKey?: boolean }): Promise; reconstructKey(): Promise; @@ -336,7 +327,7 @@ export interface ITKey extends ITKeyApi, ISerializable { export type TKeyInitArgs = { withShare?: ShareStore; - importKey?: BN; + importKey?: bigint; importEd25519Seed?: Buffer; neverInitializeNewKey?: boolean; transitionMetadata?: IMetadata; diff --git a/packages/common-types/src/baseTypes/commonTypes.ts b/packages/common-types/src/baseTypes/commonTypes.ts index e392ca7bd..7bac3a82f 100644 --- a/packages/common-types/src/baseTypes/commonTypes.ts +++ b/packages/common-types/src/baseTypes/commonTypes.ts @@ -1,9 +1,10 @@ import type { CustomAuthArgs } from "@toruslabs/customauth"; -import BN from "bn.js"; -import { curve, ec as EC } from "elliptic"; -export type EllipticPoint = curve.base.BasePoint; -export type EllipticCurve = EC; +import Point from "../base/Point"; +import { HexString } from "../utils"; + +// export type EllipticPoint = curve.base.BasePoint; +// export type EllipticCurve = EC; export type PubKeyType = "ecc"; @@ -12,8 +13,6 @@ export type PolynomialID = string; export type PolyIDAndShares = [PolynomialID, string[]]; -export type BNString = string | BN; - export interface EncryptedMessage { ciphertext: string; ephemPublicKey: string; @@ -38,25 +37,24 @@ export interface ISerializable { } export interface IPoint extends ISerializable { - x: BN | null; - y: BN | null; - encode(enc: string, params?: unknown): Buffer; + x: bigint | null; + y: bigint | null; } export interface IServiceProvider extends ISerializable { enableLogging: boolean; - postboxKey: BN; + postboxKey: bigint; serviceProviderName: string; - migratableKey?: BN | null; + migratableKey?: bigint | null; encrypt(msg: Buffer): Promise; decrypt(msg: EncryptedMessage): Promise; retrievePubKey(type: PubKeyType): Buffer; - retrievePubKeyPoint(): EllipticPoint; - sign(msg: BNString): string; + retrievePubKeyPoint(): Point; + sign(msg: HexString): string; } export type TorusStorageLayerAPIParams = { pub_key_X: string; @@ -69,15 +67,15 @@ export type TorusStorageLayerAPIParams = { export interface IStorageLayer extends ISerializable { storageLayerName: string; - getMetadata(params: { serviceProvider?: IServiceProvider; privKey?: BN }): Promise; + getMetadata(params: { serviceProvider?: IServiceProvider; privKey?: bigint }): Promise; - setMetadata(params: { input: T; serviceProvider?: IServiceProvider; privKey?: BN }): Promise<{ message: string }>; + setMetadata(params: { input: T; serviceProvider?: IServiceProvider; privKey?: bigint }): Promise<{ message: string }>; - setMetadataStream(params: { input: T[]; serviceProvider?: IServiceProvider; privKey?: BN[] }): Promise<{ message: string }>; + setMetadataStream(params: { input: T[]; serviceProvider?: IServiceProvider; privKey?: bigint[] }): Promise<{ message: string }>; - acquireWriteLock(params: { serviceProvider?: IServiceProvider; privKey?: BN }): Promise<{ status: number; id?: string }>; + acquireWriteLock(params: { serviceProvider?: IServiceProvider; privKey?: bigint }): Promise<{ status: number; id?: string }>; - releaseWriteLock(params: { id: string; serviceProvider?: IServiceProvider; privKey?: BN }): Promise<{ status: number }>; + releaseWriteLock(params: { id: string; serviceProvider?: IServiceProvider; privKey?: bigint }): Promise<{ status: number }>; } export type TorusStorageLayerArgs = { diff --git a/packages/common-types/src/utils.ts b/packages/common-types/src/utils.ts index 205bbdabd..baf40d21c 100644 --- a/packages/common-types/src/utils.ts +++ b/packages/common-types/src/utils.ts @@ -1,12 +1,35 @@ +import { bytesToHex, hexToBytes } from "@noble/curves/abstract/utils"; +import { secp256k1 } from "@noble/curves/secp256k1"; import { serializeError } from "@toruslabs/customauth"; -import { decrypt as ecDecrypt, encrypt as ecEncrypt, generatePrivate } from "@toruslabs/eccrypto"; +import { decrypt as ecDecrypt, encrypt as ecEncrypt } from "@toruslabs/eccrypto"; import { keccak256, toChecksumAddress } from "@toruslabs/torus.js"; -import BN from "bn.js"; -import { ec as EC } from "elliptic"; import { EncryptedMessage } from "./baseTypes/commonTypes"; -export const secp256k1 = new EC("secp256k1"); +export type HexString = `0x${string}`; + +export const prefix0x = (value: string): HexString => { + if (value.startsWith("0x")) { + return value as HexString; + } + return `0x${value}`; +}; + +export const strip0x = (value: string): string => { + if (value.startsWith("0x")) { + return value.substring(2); + } + return value; +}; + +export const bigIntToHex = (value: bigint): HexString => { + return `0x${value.toString(16)}`; +}; + +export function bigIntUmod(a: bigint, m: bigint): bigint { + // return a % m; + return ((a % m) + m) % m; +} // Wrappers around ECC encrypt/decrypt to use the hex serialization // TODO: refactor to take BN @@ -14,19 +37,19 @@ export async function encrypt(publicKey: Buffer, msg: Buffer): Promise { +export async function decrypt(privKey: Buffer, msg: EncryptedMessage): Promise { const bufferEncDetails = { - ciphertext: Buffer.from(msg.ciphertext, "hex"), - ephemPublicKey: Buffer.from(msg.ephemPublicKey, "hex"), - iv: Buffer.from(msg.iv, "hex"), - mac: Buffer.from(msg.mac, "hex"), + ciphertext: hexToBytes(msg.ciphertext), + ephemPublicKey: hexToBytes(msg.ephemPublicKey), + iv: hexToBytes(msg.iv), + mac: hexToBytes(msg.mac), }; return ecDecrypt(privKey, bufferEncDetails); @@ -70,9 +93,9 @@ export function normalize(input: number | string): string { return `0x${hexString}`; } -export function generatePrivateExcludingIndexes(shareIndexes: Array): BN { - const key = new BN(generatePrivate()); - if (shareIndexes.find((el) => el.eq(key))) { +export function generatePrivateExcludingIndexes(shareIndexes: Array): bigint { + const key = BigInt(prefix0x(bytesToHex(secp256k1.utils.randomPrivateKey()))); + if (shareIndexes.find((el) => el === key)) { return generatePrivateExcludingIndexes(shareIndexes); } return key; diff --git a/packages/common-types/test/test.js b/packages/common-types/test/test.js deleted file mode 100644 index 003ce2bbb..000000000 --- a/packages/common-types/test/test.js +++ /dev/null @@ -1,61 +0,0 @@ -import { generatePrivate } from "@toruslabs/eccrypto"; -import { fail } from "assert"; -import BN from "bn.js"; - -import { getPubKeyPoint, Point, Polynomial } from "../src/base"; -import { secp256k1 } from "../src/utils"; - -describe("polynomial", function () { - it("#should polyEval indexes correctly", async function () { - const polyArr = [new BN(5), new BN(2)]; - const poly = new Polynomial(polyArr); - const result = poly.polyEval(new BN(1)); - if (result.cmp(new BN(7)) !== 0) { - fail("poly result should equal 7"); - } - }); -}); - -describe("Point", function () { - it("#should encode into elliptic format on encode", async function () { - const secret = new BN(generatePrivate()); - const point = getPubKeyPoint(secret); - const result = point.toSEC1(secp256k1, true); - if (result.toString("hex").slice(2) !== point.x.toString("hex", 64)) { - fail(`elliptic format x should be equal ${secret} ${result.toString("hex")} ${point.x.toString("hex")} ${secret.umod(secp256k1.n)}`); - } - }); - - it("#should decode into point for elliptic format compressed", async function () { - const secret = new BN(generatePrivate()); - const point = getPubKeyPoint(secret); - const result = point.toSEC1(secp256k1, true); - if (result.toString("hex").slice(2) !== point.x.toString("hex", 64)) { - fail("elliptic format x should be equal"); - } - const key = secp256k1.keyFromPublic(result.toString("hex"), "hex"); - if (point.x.cmp(key.pub.x) !== 0) { - fail(" x should be equal"); - } - if (point.y.cmp(key.pub.y) !== 0) { - fail(" x should be equal"); - } - }); - - it("#should decode into point for fromSEC1", async function () { - const secret = new BN(generatePrivate()); - const point = getPubKeyPoint(secret); - const result = point.toSEC1(secp256k1, true); - if (result.toString("hex").slice(2) !== point.x.toString("hex", 64)) { - fail("elliptic format x should be equal"); - } - - const key = Point.fromSEC1(secp256k1, result.toString("hex")); - if (point.x.cmp(key.x) !== 0) { - fail(" x should be equal"); - } - if (point.y.cmp(key.y) !== 0) { - fail(" x should be equal"); - } - }); -}); diff --git a/packages/common-types/test/test.ts b/packages/common-types/test/test.ts new file mode 100644 index 000000000..09ce62bc7 --- /dev/null +++ b/packages/common-types/test/test.ts @@ -0,0 +1,63 @@ +import { describe, it } from "node:test"; + +import { bytesToHex, bytesToNumberBE } from "@noble/curves/abstract/utils"; +import { secp256k1 } from "@noble/curves/secp256k1"; +import { fail } from "assert"; + +import { Point, Polynomial } from "../src/base"; +import { curveType } from "../src/base/Point"; +describe("common types", function () { + describe("polynomial", function () { + it("#should polyEval indexes correctly", async function () { + const polyArr = [BigInt(5), BigInt(2)]; + const poly = new Polynomial(polyArr); + const result = poly.polyEval(BigInt(1)); + if (result !== BigInt(7)) { + fail("poly result should equal 7"); + } + }); + }); + + describe("Point", function () { + it("#should encode into elliptic format on encode", async function () { + const secret = secp256k1.utils.randomPrivateKey(); + const point = Point.fromScalar(curveType.secp256k1, bytesToHex(secret)); + const result = point.toSEC1(curveType.secp256k1, true); + if (bytesToNumberBE(result.subarray(1)) !== point.x) { + fail(`elliptic format x should be equal ${secret} ${result} ${point.x} `); + } + }); + + it("#should decode into point for elliptic format compressed", async function () { + const secret = secp256k1.utils.randomPrivateKey(); + const point = Point.fromScalar(curveType.secp256k1, bytesToHex(secret)); + const result = point.toSEC1(curveType.secp256k1, true); + if (bytesToNumberBE(result.subarray(1)) !== point.x) { + fail("elliptic format x should be equal"); + } + const key = secp256k1.ProjectivePoint.fromHex(result); + if (point.x !== key.x) { + fail(" x should be equal"); + } + if (point.y !== key.y) { + fail(" x should be equal"); + } + }); + + it("#should decode into point for fromSEC1", async function () { + const secret = secp256k1.utils.randomPrivateKey(); + const point = Point.fromScalar(curveType.secp256k1, bytesToHex(secret)); + const result = point.toSEC1(curveType.secp256k1, false); + if (bytesToNumberBE(result.subarray(1, 33)) !== point.x) { + fail("elliptic format x should be equal"); + } + const key = secp256k1.ProjectivePoint.fromHex(result); + if (point.x !== key.x) { + fail(" x should be equal"); + } + if (point.y !== key.y) { + fail(" x should be equal"); + } + }); + }); +}); diff --git a/packages/service-provider-base/src/ServiceProviderBase.ts b/packages/service-provider-base/src/ServiceProviderBase.ts index 36dc93209..90fd70309 100644 --- a/packages/service-provider-base/src/ServiceProviderBase.ts +++ b/packages/service-provider-base/src/ServiceProviderBase.ts @@ -1,15 +1,12 @@ +import { hexToNumber } from "@noble/curves/abstract/utils"; import { - BNString, decrypt as decryptUtils, encrypt as encryptUtils, EncryptedMessage, - getPubKeyECC, IServiceProvider, PubKeyType, ServiceProviderArgs, StringifiedType, - toPrivKeyEC, - toPrivKeyECC, } from "@tkey/common-types"; import BN from "bn.js"; import { curve } from "elliptic"; @@ -18,15 +15,15 @@ class ServiceProviderBase implements IServiceProvider { enableLogging: boolean; // For easy serialization - postboxKey: BN; + postboxKey: bigint; serviceProviderName: string; - migratableKey: BN | null = null; + migratableKey: bigint | null = null; constructor({ enableLogging = false, postboxKey }: ServiceProviderArgs) { this.enableLogging = enableLogging; - this.postboxKey = new BN(postboxKey, "hex"); + this.postboxKey = hexToNumber(postboxKey); this.serviceProviderName = "ServiceProviderBase"; } @@ -37,6 +34,14 @@ class ServiceProviderBase implements IServiceProvider { return new ServiceProviderBase({ enableLogging, postboxKey }); } + toJSON(): StringifiedType { + return { + enableLogging: this.enableLogging, + postboxKey: this.postboxKey.toString("hex"), + serviceProviderName: this.serviceProviderName, + }; + } + async encrypt(msg: Buffer): Promise { const publicKey = this.retrievePubKey("ecc"); return encryptUtils(publicKey, msg); @@ -62,14 +67,6 @@ class ServiceProviderBase implements IServiceProvider { const sig = toPrivKeyEC(this.postboxKey).sign(tmp.toString("hex")); return Buffer.from(sig.r.toString(16, 64) + sig.s.toString(16, 64) + new BN(0).toString(16, 2), "hex").toString("base64"); } - - toJSON(): StringifiedType { - return { - enableLogging: this.enableLogging, - postboxKey: this.postboxKey.toString("hex"), - serviceProviderName: this.serviceProviderName, - }; - } } export default ServiceProviderBase; diff --git a/packages/storage-layer-torus/package.json b/packages/storage-layer-torus/package.json index e0a47c352..5f628356d 100644 --- a/packages/storage-layer-torus/package.json +++ b/packages/storage-layer-torus/package.json @@ -22,7 +22,7 @@ "url": "git+https://github.com/tkey/tkey.git" }, "scripts": { - "test": "cross-env MOCKED=true mocha --config ../../.mocharc.json ", + "test": "node --test -r esbuild-register test/*.spec.ts", "coverage": "nyc npm test", "coverage-production": "nyc npm run test-production", "test-development": "cross-env MOCKED=false METADATA=http://localhost:5051 mocha --config ../../.mocharc.json ", @@ -47,7 +47,8 @@ }, "devDependencies": { "@types/bn.js": "^5.1.5", - "@types/json-stable-stringify": "^1.0.36" + "@types/json-stable-stringify": "^1.0.36", + "esbuild-register": "^3.6.0" }, "bugs": { "url": "https://github.com/tkey/tkey/issues" diff --git a/packages/storage-layer-torus/test/test.spec.ts b/packages/storage-layer-torus/test/test.spec.ts new file mode 100644 index 000000000..acef217b4 --- /dev/null +++ b/packages/storage-layer-torus/test/test.spec.ts @@ -0,0 +1,42 @@ +import { describe, it } from "node:test"; + +import { KeyType } from "@tkey/common-types"; +import assert from "assert"; +import { BN } from "bn.js"; + +import TorusStorageLayer from "../src/TorusStorageLayer"; + +const metadataURL = process.env.METADATA || "https://node-1.dev-node.web3auth.io/metadata"; + +const keyTypes = [KeyType.ed25519, KeyType.secp256k1]; +keyTypes.forEach((keyType) => { + describe(`TorusStorageLayer test, keyType ${keyType}`, function () { + it("#should encrypt and decrypt correctly", async function () { + let rand = new Uint8Array(32); + rand = crypto.getRandomValues(rand); + + const privKey = new BN(rand); + const tmp = new BN(123); + const message = tmp.toBuffer(); + const storageLayer = new TorusStorageLayer({ hostUrl: metadataURL }); + await storageLayer.setMetadata({ input: message, privKey }); + + const readResult = (await storageLayer.getMetadata({ privKey })) as { data: string }; + assert(Buffer.from(readResult.data).equals(Buffer.from(message))); + }); + + it("#should set bulk stream ", async function () { + let rand = new Uint8Array(32); + rand = crypto.getRandomValues(rand); + + const privKey = new BN(rand); + const tmp = new BN(123); + const message = tmp.toBuffer(); + const storageLayer = new TorusStorageLayer({ hostUrl: metadataURL }); + await storageLayer.setMetadataStream({ input: [message, message.subarray(3)], privKey: [privKey, privKey] }); + + const readResult = (await storageLayer.getMetadata({ privKey })) as { data: string }; + assert(Buffer.from(readResult.data).equals(Buffer.from(message.subarray(3)))); + }); + }); +});