diff --git a/package.json b/package.json index bf9fe3f..724aed4 100644 --- a/package.json +++ b/package.json @@ -95,6 +95,7 @@ "dependencies": { "@scure/bip32": "^1.4.0", "@types/node": "^16.11.6", + "base-x": "^4.0.0", "bip39": "^3.0.4", "bip44-constants": "^123.0.0", "bn.js": "^5.2.1", @@ -104,8 +105,7 @@ "ethers": "^6.13.1", "jcc_common": "^0.1.0", "lockr": "^0.8.5", - "node-polyfill-webpack-plugin": "^2.0.1", - "wif": "^4.0.0" + "node-polyfill-webpack-plugin": "^2.0.1" }, "nyc": { "check-coverage": true, diff --git a/src/hd/eos.plugin.ts b/src/hd/eos.plugin.ts index 1c4c17e..a202469 100644 --- a/src/hd/eos.plugin.ts +++ b/src/hd/eos.plugin.ts @@ -1,15 +1,14 @@ -import { filterOx } from "jcc_common"; import { IHDPlugin, IKeyPair } from "../types"; import { sha256 } from "@noble/hashes/sha256"; -import { ripemd160 } from "@noble/hashes/ripemd160"; -import base58 from "bs58"; import { PublicKey } from "../minify-eosjs/PublicKey"; import { PrivateKey } from "../minify-eosjs/PrivateKey"; import { Signature } from "../minify-eosjs/Signature"; -import wif from "wif"; +import { KeyType, publicKeyToLegacyString, privateKeyToLegacyString } from "../minify-eosjs/eosjs-numeric"; +import { stripHexPrefix } from "../minify-ethereumjs-util/internal"; export interface IEosPlugin extends IHDPlugin { checkPrivateKey(privateKey: string): string; + privateKeyToLegacyString(privateKey: string): string; } export const plugin: IEosPlugin = { @@ -17,19 +16,27 @@ export const plugin: IEosPlugin = { // check and cut swtc keypair lib add prefix 00 return privateKey.length === 66 ? privateKey.substring(2) : privateKey; }, + privateKeyToLegacyString(privateKey: string): string { + const priv = plugin.checkPrivateKey(stripHexPrefix(privateKey)); + const buffer = Buffer.from(priv, "hex"); + const eosPrivateKey = privateKeyToLegacyString({ + data: Uint8Array.from(buffer), + type: KeyType.k1 + }); + return eosPrivateKey; + }, address(key: IKeyPair): string { if (key.privateKey) { - const privateKey = plugin.checkPrivateKey(key.privateKey); - const buffer = Buffer.from(privateKey, "hex"); - const eosPrivateKey = wif.encode(128, buffer, false); + const eosPrivateKey = plugin.privateKeyToLegacyString(key.privateKey); return PrivateKey.fromString(eosPrivateKey) .getPublicKey() .toLegacyString(); } if (key.publicKey) { - const rawPublicKey = Buffer.from(key.publicKey, "hex"); - const checksum = ripemd160(rawPublicKey).slice(0, 4); - return "EOS" + base58.encode(Buffer.concat([rawPublicKey, Buffer.from(checksum)])); + return publicKeyToLegacyString({ + data: Uint8Array.from(Buffer.from(key.publicKey, "hex")), + type: KeyType.k1 + }); } return null; }, @@ -44,9 +51,7 @@ export const plugin: IEosPlugin = { isValidSecret(secret: string): boolean { try { - const privateKey = plugin.checkPrivateKey(filterOx(secret)); - const buffer = Buffer.from(privateKey, "hex"); - const eosPrivateKey = wif.encode(128, buffer, false); + const eosPrivateKey = plugin.privateKeyToLegacyString(secret); return PrivateKey.fromString(eosPrivateKey).isValid() as boolean; } catch (_) { return false; @@ -67,8 +72,7 @@ export const plugin: IEosPlugin = { * @returns signature string */ sign(message: string, privateKey: string): string { - const buffer = Buffer.from(plugin.checkPrivateKey(filterOx(privateKey)), "hex"); - const eosPrivateKey = wif.encode(128, buffer, false); + const eosPrivateKey = plugin.privateKeyToLegacyString(privateKey); const pk = PrivateKey.fromString(eosPrivateKey); return pk.sign(message).toString(); }, diff --git a/src/minify-eosjs/eosjs-numeric.ts b/src/minify-eosjs/eosjs-numeric.ts index f7a8ec0..e2344ae 100644 --- a/src/minify-eosjs/eosjs-numeric.ts +++ b/src/minify-eosjs/eosjs-numeric.ts @@ -6,6 +6,7 @@ */ import { ripemd160 } from "@noble/hashes/ripemd160"; +import { sha256 } from "@noble/hashes/sha256"; const base58Chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; @@ -260,3 +261,46 @@ export const signatureToString = (signature: Key): string => { throw new Error("unrecognized signature format"); } }; + +export const privateKeyToLegacyString = (key: Key): string => { + if (key.type === KeyType.k1 && key.data.length === privateKeyDataSize) { + const whole = [] as number[]; + whole.push(128); + key.data.forEach((byte) => whole.push(byte)); + const digest = new Uint8Array( + sha256 + .create() + .update( + sha256 + .create() + .update(Buffer.from(whole)) + .digest() + ) + .digest() + ); + + const result = new Uint8Array(privateKeyDataSize + 5); + for (let i = 0; i < whole.length; i++) { + result[i] = whole[i]; + } + for (let i = 0; i < 4; i++) { + result[i + whole.length] = digest[i]; + } + return binaryToBase58(result); + } else if (key.type === KeyType.r1 || key.type === KeyType.wa) { + throw new Error("Key format not supported in legacy conversion"); + } else { + throw new Error("unrecognized public key format"); + } +}; + +/** Convert `key` to string (base-58) form */ +export const privateKeyToString = (key: Key): string => { + if (key.type === KeyType.r1) { + return keyToString(key, "R1", "PVT_R1_"); + } else if (key.type === KeyType.k1) { + return keyToString(key, "K1", "PVT_K1_"); + } else { + throw new Error("unrecognized private key format"); + } +}; diff --git a/webpack.config.js b/webpack.config.js index 53deccb..58e259f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -15,10 +15,6 @@ const config = { target: "web", resolve: { extensions: [".js", ".ts"], - alias: { - "bn.js": path.resolve(__dirname, "node_modules/bn.js"), - "base-x": path.resolve(__dirname, "node_modules/base-x") - }, fallback: { tls: false, net: false, diff --git a/yarn.lock b/yarn.lock index 43a56a8..aab9594 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3188,25 +3188,6 @@ __metadata: languageName: node linkType: hard -"bs58@npm:^5.0.0": - version: 5.0.0 - resolution: "bs58@npm:5.0.0" - dependencies: - base-x: "npm:^4.0.0" - checksum: 0d1b05630b11db48039421b5975cb2636ae0a42c62f770eec257b2e5c7d94cb5f015f440785f3ec50870a6e9b1132b35bd0a17c7223655b22229f24b2a3491d1 - languageName: node - linkType: hard - -"bs58check@npm:^3.0.1": - version: 3.0.1 - resolution: "bs58check@npm:3.0.1" - dependencies: - "@noble/hashes": "npm:^1.2.0" - bs58: "npm:^5.0.0" - checksum: a01f62351d17cea5f6607f75f6b4b79d3473d018c52f1dfa6f449751062bb079ebfd556ea81c453de657102ab8c5a6b78620161f21ae05f0e5a43543e0447700 - languageName: node - linkType: hard - "bser@npm:2.1.1": version: 2.1.1 resolution: "bser@npm:2.1.1" @@ -5552,6 +5533,7 @@ __metadata: "@typescript-eslint/parser": "npm:^7.12.0" babel-jest: "npm:^29.7.0" babel-loader: "npm:^9.1.3" + base-x: "npm:^4.0.0" bip39: "npm:^3.0.4" bip44-constants: "npm:^123.0.0" bn.js: "npm:^5.2.1" @@ -5589,7 +5571,6 @@ __metadata: webpack: "npm:^5.89.0" webpack-bundle-analyzer: "npm:^4.10.1" webpack-cli: "npm:^5.1.4" - wif: "npm:^4.0.0" languageName: unknown linkType: soft @@ -8908,15 +8889,6 @@ __metadata: languageName: node linkType: hard -"wif@npm:^4.0.0": - version: 4.0.0 - resolution: "wif@npm:4.0.0" - dependencies: - bs58check: "npm:^3.0.1" - checksum: bc267d1eac5a29b62d8356cca28760411ab489d863cfcd622c64552b40e9c50e027f140ef969cb87a60b8cf817f044f86d8a9971a2c261b934abfe21de2c490e - languageName: node - linkType: hard - "wildcard@npm:^2.0.0": version: 2.0.1 resolution: "wildcard@npm:2.0.1"