From 741eb702451f7a2b354046bbc8cb4a1623f22ff9 Mon Sep 17 00:00:00 2001 From: "luk.lu" Date: Fri, 12 Aug 2022 12:03:02 +0800 Subject: [PATCH] u --- ticc.js | 52 ++++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/ticc.js b/ticc.js index 8305305..2f71995 100644 --- a/ticc.js +++ b/ticc.js @@ -229,7 +229,7 @@ class TicCrypto { return { iv: iv.toString('hex'), ciphertext } // 有 iv,显然每次结果不一样 } } else if (keytype === 'seckey') { - // 尚未走通,不能使用 ticc 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeypairs() 生成的 rsa 公私钥 + // 尚未走通,不能使用 ticc 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeyPair('rsa') 生成的 rsa 公私钥 let seckeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。 return crypto.privateEncrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。 } else if (keytype === 'pubkey') { @@ -433,10 +433,9 @@ class TicCrypto { * @return {Object} {pubkey, seckey,} * @memberof TicCrypto */ - static secword_to_keypair ({ secword, coin, pass, pathRoot, path, tool, hasher } = {}) { + static secword_to_keypair ({ secword, coin, pass, pathRoot, pathIndex, path, tool, hasher } = {}) { // coin 币种; // passphase 密码,默认为空; - // path==='master' 生成 HD master key,不定义则默认为相应币种的第一对公私钥。 // path 规范为 m/Purpose'/CoinType'/Account'/Change/Index (https://learnblockchain.cn/2018/09/28/hdwallet/), 其中 // Purpose===44 for BIP44, // CoinType===0 for BTC, 60 for ETH. (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) @@ -456,8 +455,6 @@ class TicCrypto { .digest() let keypair = nacl.sign.keyPair.fromSeed(hashBuf) // nacl.sign.keyPair.fromSeed 要求32字节的种子,而 this.secword2seed生成的是64字节种子,所以要先做一次sha256 return { - coin: coin, - secword: secword, pubkey: Buffer.from(keypair.publicKey).toString('hex'), // 测试过 不能直接keypair.publicKey.toString('hex'),不是buffer类型 seckey: Buffer.from(keypair.secretKey).toString('hex'), // nacl.sign.keyPair.fromSeed 得到的 seckey 是64字节的,不同于比特币/以太坊的32字节密钥。 tool, @@ -467,16 +464,19 @@ class TicCrypto { let hdmaster = hdkey.fromMasterSeed(Buffer.from(this.secword_to_seed({ secword, pass }), 'hex')) // 和 new BitcoreMnemonic(secword).toHDPrivateKey 求出的公私钥一样! // let hdmaster=new BitcoreMnemonic(secword).toHDPrivateKey(pass) // 和 ethers.HDNode.fromMnemonic(secword)的公私钥一样。而 ethers.HDNode.fromMnemonic(secword).derivePath("m/44'/60'/0'/0/0")的公私钥===ethers.Wallet.fromMnemonic(secword [,"m/44'/60'/0'/0/0"]) let key = hdmaster - if (path === 'master') { - key = hdmaster - } else { - // 指定了路径 path 例如 "m/0/2147483647'/1" 则用 path;没有指定路径 则调用 root_to_path() 来获取路径, 例如 不存在 pathRoot 时获取的是根路径 "m/44'/0'/0'/0/0" 或 "m/44'/60'/0'/0/0" - path = path || this.root_to_path({ pathRoot, coin }) + if (path) { + // 指定了path 例如 "m/0/2147483647'/1" 则用 path 例如 不存在 pathRoot 时获取的是根路径 "m/44'/0'/0'/0/0" 或 "m/44'/60'/0'/0/0" key = hdmaster.derive(path) + } else if (pathRoot) { + // 指定了 pathRoot 则调用 root_to_path() 来获取路径 + path = this.root_to_path({ pathRoot, pathIndex, coin }) + key = hdmaster.derive(path) + } else { + // 没有指定 path 或 pathRoot,则返回主钥 + path = '' + key = hdmaster } return { - coin, - secword, path, seckey: key.privateKey.toString('hex'), // 或者 key.toJSON().privateKey。或者 key.privateKey.slice(2) 删除开头的'0x'如果是ethers.HDNode.fromMnemonic(secword)的结果 pubkey: key.publicKey.toString('hex'), @@ -494,11 +494,11 @@ class TicCrypto { * @return {String} path * @memberof TicCrypto */ - static root_to_path ({ pathRoot, coin } = {}) { + static root_to_path ({ pathRoot, pathIndex, coin = my.COIN } = {}) { // 路径规范 BIP44: m/Purpose'/Coin'/Account'/Change/Index, // 但实际上 Purpose, Coin 都可任意定;' 可有可无; - // Account/Change/Index 最大到 parseInt(0x7FFFFFFF, 16) // 后面还可继续延伸 /xxx/xxx/xxx/...... + // 每个数字最大到 parseInt("0x7FFFFFFF", 16)=parseInt(0x7FFFFFFF)=2147483647,更大就报错。 let path if (pathRoot) { let pathHash = this.hash_easy(pathRoot, { hasher: 'md5' }) @@ -510,14 +510,18 @@ class TicCrypto { let part5 = parseInt(pathHash.slice(30, 32), 16) path = `${part0}'/${part1}/${part2}/${part3}/${part4}/${part5}` } else { + // 本方法也可用来生成默认的第0个路径,例如 "m/44'/0'/0'/0/0" path = "0'/0/0" } - coin = coin?.toUpperCase() || my.COIN + if (Number.isInteger(pathIndex) && 0 <= pathIndex && pathIndex <= 0x7fffffff) { + path += `/${pathIndex}` + } + coin = coin?.toUpperCase() if (coin === 'BTC') { return `m/44'/0'/${path}` } else if (coin === 'ETH') { return `m/44'/60'/${path}` - } else if (coin === 'TIC' || !coin) { + } else if (coin === 'TIC') { return `m/44'/60000'/${path}` } else if (/[A-Z]{3}/.test(coin)) { return `m/44'/60${this.alpha_to_digit(coin)}'/${path}` @@ -549,10 +553,10 @@ class TicCrypto { * @return {Object} * @memberof TicCrypto */ - static secword_to_account ({ secword, coin, pass, pathRoot, path, tool, hasher } = {}) { + static secword_to_account ({ secword, coin = my.COIN, pass, pathRoot, pathIndex, path, tool, hasher } = {}) { // account 比 keypair 多了 address 字段。 - coin = coin?.toUpperCase() || my.COIN - let kp = this.secword_to_keypair({ secword, coin, pass, pathRoot, path, tool, hasher }) + coin = coin?.toUpperCase() + let kp = this.secword_to_keypair({ secword, coin, pass, pathRoot, pathIndex, path, tool, hasher }) if (kp) { if (coin === 'ETH') { let uncompressedPubkey = this.decompress_pubkey(kp.pubkey) @@ -560,7 +564,7 @@ class TicCrypto { } else { kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin }) } - return kp + return Object.assign(kp, { coin, secword }) } return null } @@ -574,9 +578,9 @@ class TicCrypto { * @return {String} address * @memberof TicCrypto */ - static secword_to_address ({ secword, coin, world, pass, pathRoot, path, tool, hasher } = {}) { + static secword_to_address ({ secword, coin, world, pass, pathRoot, pathIndex, path, tool, hasher } = {}) { coin = coin?.toUpperCase() || my.COIN - let kp = this.secword_to_keypair({ secword, coin, pass, pathRoot, path, tool, hasher }) + let kp = this.secword_to_keypair({ secword, coin, pass, pathRoot, pathIndex, path, tool, hasher }) if (kp) { let address if (coin === 'ETH') { @@ -935,9 +939,9 @@ class TicCrypto { * @return {*} * @memberof TicCrypto */ - static randomize_account ({ lang, wordCount, coin, pass, pathRoot, path, tool, hasher } = {}) { + static randomize_account ({ lang, wordCount, coin, pass, pathRoot, pathIndex, path, tool, hasher } = {}) { let secword = this.randomize_secword({ lang, wordCount }) - return this.secword_to_account({ secword, coin, pass, pathRoot, path, tool, hasher }) + return this.secword_to_account({ secword, coin, pass, pathRoot, pathIndex, path, tool, hasher }) } /**