This commit is contained in:
陆柯 2022-08-12 12:03:02 +08:00
parent a9dac7e858
commit 741eb70245

52
ticc.js
View File

@ -229,7 +229,7 @@ class TicCrypto {
return { iv: iv.toString('hex'), ciphertext } // 有 iv显然每次结果不一样 return { iv: iv.toString('hex'), ciphertext } // 有 iv显然每次结果不一样
} }
} else if (keytype === 'seckey') { } 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字节。 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。每次结果都一样。 return crypto.privateEncrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
} else if (keytype === 'pubkey') { } else if (keytype === 'pubkey') {
@ -433,10 +433,9 @@ class TicCrypto {
* @return {Object} {pubkey, seckey,} * @return {Object} {pubkey, seckey,}
* @memberof TicCrypto * @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 币种; // coin 币种;
// passphase 密码,默认为空; // passphase 密码,默认为空;
// path==='master' 生成 HD master key不定义则默认为相应币种的第一对公私钥。
// path 规范为 m/Purpose'/CoinType'/Account'/Change/Index (https://learnblockchain.cn/2018/09/28/hdwallet/), 其中 // path 规范为 m/Purpose'/CoinType'/Account'/Change/Index (https://learnblockchain.cn/2018/09/28/hdwallet/), 其中
// Purpose===44 for BIP44, // Purpose===44 for BIP44,
// CoinType===0 for BTC, 60 for ETH. (https://github.com/satoshilabs/slips/blob/master/slip-0044.md) // CoinType===0 for BTC, 60 for ETH. (https://github.com/satoshilabs/slips/blob/master/slip-0044.md)
@ -456,8 +455,6 @@ class TicCrypto {
.digest() .digest()
let keypair = nacl.sign.keyPair.fromSeed(hashBuf) // nacl.sign.keyPair.fromSeed 要求32字节的种子而 this.secword2seed生成的是64字节种子所以要先做一次sha256 let keypair = nacl.sign.keyPair.fromSeed(hashBuf) // nacl.sign.keyPair.fromSeed 要求32字节的种子而 this.secword2seed生成的是64字节种子所以要先做一次sha256
return { return {
coin: coin,
secword: secword,
pubkey: Buffer.from(keypair.publicKey).toString('hex'), // 测试过 不能直接keypair.publicKey.toString('hex')不是buffer类型 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字节密钥。 seckey: Buffer.from(keypair.secretKey).toString('hex'), // nacl.sign.keyPair.fromSeed 得到的 seckey 是64字节的不同于比特币/以太坊的32字节密钥。
tool, 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 = 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 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 let key = hdmaster
if (path === 'master') { if (path) {
key = hdmaster // 指定了path 例如 "m/0/2147483647'/1" 则用 path 例如 不存在 pathRoot 时获取的是根路径 "m/44'/0'/0'/0/0" 或 "m/44'/60'/0'/0/0"
} 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 })
key = hdmaster.derive(path) 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 { return {
coin,
secword,
path, path,
seckey: key.privateKey.toString('hex'), // 或者 key.toJSON().privateKey。或者 key.privateKey.slice(2) 删除开头的'0x'如果是ethers.HDNode.fromMnemonic(secword)的结果 seckey: key.privateKey.toString('hex'), // 或者 key.toJSON().privateKey。或者 key.privateKey.slice(2) 删除开头的'0x'如果是ethers.HDNode.fromMnemonic(secword)的结果
pubkey: key.publicKey.toString('hex'), pubkey: key.publicKey.toString('hex'),
@ -494,11 +494,11 @@ class TicCrypto {
* @return {String} path * @return {String} path
* @memberof TicCrypto * @memberof TicCrypto
*/ */
static root_to_path ({ pathRoot, coin } = {}) { static root_to_path ({ pathRoot, pathIndex, coin = my.COIN } = {}) {
// 路径规范 BIP44: m/Purpose'/Coin'/Account'/Change/Index, // 路径规范 BIP44: m/Purpose'/Coin'/Account'/Change/Index,
// 但实际上 Purpose, Coin 都可任意定;' 可有可无; // 但实际上 Purpose, Coin 都可任意定;' 可有可无;
// Account/Change/Index 最大到 parseInt(0x7FFFFFFF, 16)
// 后面还可继续延伸 /xxx/xxx/xxx/...... // 后面还可继续延伸 /xxx/xxx/xxx/......
// 每个数字最大到 parseInt("0x7FFFFFFF", 16)=parseInt(0x7FFFFFFF)=2147483647更大就报错。
let path let path
if (pathRoot) { if (pathRoot) {
let pathHash = this.hash_easy(pathRoot, { hasher: 'md5' }) let pathHash = this.hash_easy(pathRoot, { hasher: 'md5' })
@ -510,14 +510,18 @@ class TicCrypto {
let part5 = parseInt(pathHash.slice(30, 32), 16) let part5 = parseInt(pathHash.slice(30, 32), 16)
path = `${part0}'/${part1}/${part2}/${part3}/${part4}/${part5}` path = `${part0}'/${part1}/${part2}/${part3}/${part4}/${part5}`
} else { } else {
// 本方法也可用来生成默认的第0个路径例如 "m/44'/0'/0'/0/0"
path = "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') { if (coin === 'BTC') {
return `m/44'/0'/${path}` return `m/44'/0'/${path}`
} else if (coin === 'ETH') { } else if (coin === 'ETH') {
return `m/44'/60'/${path}` return `m/44'/60'/${path}`
} else if (coin === 'TIC' || !coin) { } else if (coin === 'TIC') {
return `m/44'/60000'/${path}` return `m/44'/60000'/${path}`
} else if (/[A-Z]{3}/.test(coin)) { } else if (/[A-Z]{3}/.test(coin)) {
return `m/44'/60${this.alpha_to_digit(coin)}'/${path}` return `m/44'/60${this.alpha_to_digit(coin)}'/${path}`
@ -549,10 +553,10 @@ class TicCrypto {
* @return {Object} * @return {Object}
* @memberof TicCrypto * @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 字段。 // account 比 keypair 多了 address 字段。
coin = coin?.toUpperCase() || my.COIN coin = coin?.toUpperCase()
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) { if (kp) {
if (coin === 'ETH') { if (coin === 'ETH') {
let uncompressedPubkey = this.decompress_pubkey(kp.pubkey) let uncompressedPubkey = this.decompress_pubkey(kp.pubkey)
@ -560,7 +564,7 @@ class TicCrypto {
} else { } else {
kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin }) kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin })
} }
return kp return Object.assign(kp, { coin, secword })
} }
return null return null
} }
@ -574,9 +578,9 @@ class TicCrypto {
* @return {String} address * @return {String} address
* @memberof TicCrypto * @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 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) { if (kp) {
let address let address
if (coin === 'ETH') { if (coin === 'ETH') {
@ -935,9 +939,9 @@ class TicCrypto {
* @return {*} * @return {*}
* @memberof TicCrypto * @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 }) 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 })
} }
/** /**