This commit is contained in:
Luk Lu
2022-07-03 16:03:09 +08:00
parent dff0b62d64
commit 5bfd536c03
4 changed files with 290 additions and 268 deletions

289
index.js
View File

@@ -45,9 +45,9 @@ my.REGEXP_ALPHABET = {
/**
*
* @class Ticrypto
* @class TicCrypto
*/
class Ticrypto {
class TicCrypto {
/**
* 测试输入数据是否可哈希混淆
*
@@ -55,9 +55,9 @@ class Ticrypto {
* @param {*} data 需要被哈希混淆的数据
* @param {*} option 可选参数
* @return {Boolean}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static isHashable (data, { strict = false } = {}) {
static is_hashable ({ data, strict = false } = {}) {
if (strict) {
return typeof data !== 'boolean' && data !== Infinity && data ? true : false // 允许大多数数据除了null、''、0、布尔值、无限数。注意 data 要放在最后,否则会被 return 直接返回,而不是返回 Boolean
}
@@ -71,9 +71,9 @@ class Ticrypto {
* @param {String} hash
* @param {Object} option [{ hasher = my.HASHER }={}]
* @return {Boolean}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static isHash (hash, { hasher = my.HASHER } = {}) {
static is_hash ({ hash, hasher = my.HASHER } = {}) {
if (my.HASHER_LIST.includes(hasher)) {
switch (hasher) {
case 'sha256':
@@ -97,10 +97,10 @@ class Ticrypto {
* @param {String} secword
* @param {Object} option [{ mode = 'strict' }={}]
* @return {Boolean}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static isSecword (secword, { mode = 'strict' } = {}) {
// 注意 not all 12 words combinations are valid for both bitcore and bip39, because there are checksum in mnemonic. 另外实际上bitcore和bip39对12, 15, 18, ... 长度的合法助记词都返回 true。
static is_secword ({ secword, mode = 'strict' } = {}) {
// 注意 not all 12 words combinations are valid for both bitcore and bip39, because there are checksum in mnemonic. 另外实际上bitcore和bip39对12, 15, 18, 21, 24 长度的合法助记词都返回 true。
//// for bitcore-mnemonic. 注意bitcore-mnemonic 对少于12词的会抛出异常很蠢。
// if (typeof secword==='string' && 12===secword.split(/ +/).length)
// return BitcoreMnemonic.isValid(secword)
@@ -124,9 +124,9 @@ class Ticrypto {
* @static
* @param {String} seckey
* @return {Boolean}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static isSeckey (seckey) {
static is_seckey (seckey) {
// 比特币、以太坊的私钥64 hex
// nacl.sign 的私钥 128 hex, nacl.box 的私钥 64 hex
return /^([a-fA-F0-9]{128}|[a-fA-F0-9]{64})$/.test(seckey)
@@ -138,9 +138,9 @@ class Ticrypto {
* @static
* @param {String} pubkey
* @return {Boolean}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static isPubkey (pubkey) {
static is_pubkey ({ pubkey } = {}) {
// 比特币的公钥:压缩型 '02|03' + 64 hex 或 无压缩型 '04' + 128 hex
// 以太坊的公钥:'02|03' + 64 hex
// nacl.sign 的公钥64 hex
@@ -153,9 +153,9 @@ class Ticrypto {
* @static
* @param {String} signature
* @return {Boolean}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static isSignature (signature) {
static is_signature (signature) {
return /^[a-fA-F0-9]{128,144}$/.test(signature) && signature.length % 2 === 0 // 128 for nacl, 140/142/144 for crypto and eccrypto in der format.
}
@@ -166,11 +166,11 @@ class Ticrypto {
* @param {*} data
* @param {option} [{ hasher = my.HASHER, salt, input = my.INPUT, output = my.OUTPUT }={}]
* @return {String}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static hash (data, { hasher = my.HASHER, salt, input = my.INPUT, output = my.OUTPUT } = {}) {
// data can be anything, but converts to string or remains be Buffer/TypedArray/DataView
if (this.isHashable(data)) {
if (this.is_hashable({ data })) {
if (typeof data !== 'string' && !(data instanceof Buffer) && !(data instanceof DataView)) data = JSON.stringify(data)
if (salt && typeof salt === 'string') data = data + this.hash(salt)
let inputEncoding = input // my.INPUT_LIST.includes(input)?input:my.INPUT // 'utf8', 'ascii' or 'latin1' for string data, default to utf8 if not specified; ignored for Buffer, TypedArray, or DataView.
@@ -190,7 +190,7 @@ class Ticrypto {
* @param {*} data
* @param {*} option [{ tool, keytype, key, input, output, cipher }={}]
* @return {String}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static async encrypt ({ data, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) {
if (tool === 'eccrypto') {
@@ -213,7 +213,7 @@ class Ticrypto {
return { iv: iv.toString('hex'), ciphertext } // 有 iv显然每次结果不一样
}
} else if (keytype === 'seckey') {
// 尚未走通,不能使用 ticrypto 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeypairs() 生成的 rsa 公私钥
// 尚未走通,不能使用 ticc 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeypairs() 生成的 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') {
@@ -230,7 +230,7 @@ class Ticrypto {
* @param {*} data
* @param {Object} option [{ keytype, key, input, output, cipher, format }={}]
* @return {String}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static async decrypt ({ data = {}, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) {
// data 应当是 encrypt 输出的数据类型
@@ -261,7 +261,7 @@ class Ticrypto {
return decrypted
}
} else if (keytype === 'seckey') {
// 尚未走通,不能使用 ticrypto 生成的 Elliptic curve 椭圆曲线算法公私钥
// 尚未走通,不能使用 ticc 生成的 Elliptic curve 椭圆曲线算法公私钥
let seckeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
return crypto.privateDecrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
} else if (keytype === 'pubkey') {
@@ -279,11 +279,11 @@ class Ticrypto {
* @param {String} seckey
* @param {Object} option [option={}]
* @return {String}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static async sign ({ data, seckey, tool = 'crypto', hasher }) {
// data can be string or buffer or object, results are the same
if (this.isHashable(data) && this.isSeckey(seckey)) {
if (this.is_hashable({ data }) && this.is_seckey(seckey)) {
if (tool === 'nacl' && seckey.length === 128) {
// 使用nacl的签名算法。注意nacl.sign需要的seckey是64字节=128字符。
let hashBuf = this.hash(data, { output: 'buf' }) // 哈希必须输出为 buffer
@@ -316,11 +316,11 @@ class Ticrypto {
* @param {String} pubkey
* @param {Object} option [option={}]
* @return {Boolean}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static async verify ({ data, signature, pubkey, tool = 'crypto', hasher }) {
// data could be anything, but converts to string or remains be Buffer/TypedArray/DataView
if (this.isHashable(data) && this.isSignature(signature) && this.isPubkey(pubkey)) {
if (this.is_hashable({ data }) && this.is_signature(signature) && this.is_pubkey({ pubkey })) {
if ('nacl' === tool && signature.length === 128) {
let bufHash = this.hash(data, { output: 'buf' })
let bufSignature = Buffer.from(signature, 'hex')
@@ -357,11 +357,11 @@ class Ticrypto {
* @param {String} pass
* @param {Object} option
* @return {Object} {pubkey, seckey, address,}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static pass2keypair (pass, { hasher } = {}) {
static pass2keypair ({ pass, hasher } = {}) {
// 如果使用其他机制例如密码、随机数不使用secword也可生成keypair
if (this.isHashable(pass)) {
if (this.is_hashable({ data: pass })) {
hasher = my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER
var hashBuf = crypto
.createHash(hasher)
@@ -383,10 +383,10 @@ class Ticrypto {
* @static
* @param {*} entropy
* @return {String}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static entropy2secword (entropy) {
// entropy could be hex string or buffer. Byte length could be of 16, 20, 24, 28, ... which outputs mnemonic of length 12, 15, 18, 21, ...
static entropy_to_secword ({ entropy } = {}) {
// entropy could be hex string or buffer. 位数可为 128/160/192/224/256 位,即 16, 20, 24, 28, 32 字节,最后可生成 12, 15, 18, 21, 24 个单词的助记词。
return bip39.entropyToMnemonic(entropy) // results are the same for the same entropy.
}
@@ -396,10 +396,10 @@ class Ticrypto {
* @static
* @param {String} secword
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static secword2entropy (secword) {
// secword could be of length 12, 15, 18, ... which outputs hex of length 32, 40, ...
static secword_to_entropy ({ secword } = {}) {
// secword could be of length 12, 15, 18, 21, 24which outputs hex of length 32, 40, 48, 56, 64.
return bip39.mnemonicToEntropy(secword) // results are the same for the same secword.
}
@@ -410,9 +410,9 @@ class Ticrypto {
* @param {String} secword
* @param {Object} option
* @return {Object} {pubkey, seckey,}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static secword2keypair (secword, { coin, pass, path, tool, hasher } = {}) {
static secword_to_keypair ({ secword, coin, pass, pathSeed, path, tool, hasher } = {}) {
// coin 币种;
// passphase 密码,默认为空;
// path==='master' 生成 HD master key不定义则默认为相应币种的第一对公私钥。
@@ -431,7 +431,7 @@ class Ticrypto {
hasher = my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER
let hashBuf = crypto
.createHash(hasher)
.update(this.secword2seed(secword, pass))
.update(this.secword_to_seed({ secword, pass }))
.digest()
let keypair = nacl.sign.keyPair.fromSeed(hashBuf) // nacl.sign.keyPair.fromSeed 要求32字节的种子而 this.secword2seed生成的是64字节种子所以要先做一次sha256
return {
@@ -443,22 +443,22 @@ class Ticrypto {
}
} else {
// 用 bip39 算法从 secword 到种子,再用 bip32 算法从种子到根私钥。这是比特币、以太坊的标准方式,结果一致。
let hdmaster = hdkey.fromMasterSeed(Buffer.from(this.secword2seed(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 key = hdmaster
if (path === 'master') {
key = hdmaster
} else {
// 指定了路径 path 例如 "m/0/2147483647'/1" 则用 path没有指定路径 则调用 seed2path() 来获取默认的根路径 例如 "m/44'/0'/0'/0/0" 或 "m/44'/60'/0'/0/0"
path = path || this.seed2path({ coin })
// 指定了路径 path 例如 "m/0/2147483647'/1" 则用 path没有指定路径 则调用 seed_to_path() 来获取路径, 例如 不存在 pathSeed 时获取的是根路径 "m/44'/0'/0'/0/0" 或 "m/44'/60'/0'/0/0"
path = path || this.seed_to_path({ seed: pathSeed, coin })
key = hdmaster.derive(path)
}
return {
coin: coin,
secword: secword,
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'),
path,
}
}
return null
@@ -471,9 +471,9 @@ class Ticrypto {
* @param {*} seed
* @param {string} option [{ coin = my.COIN }={ coin: my.COIN }]
* @return {String} path
* @memberof Ticrypto
* @memberof TicCrypto
*/
static seed2path ({ seed, coin = my.COIN } = { coin: my.COIN }) {
static seed_to_path ({ seed, coin = my.COIN } = {}) {
// 路径规范 BIP44: m/Purpose'/Coin'/Account'/Change/Index,
// 但实际上 Purpose, Coin 都可任意定;' 可有可无;
// Account/Change/Index 最大到 parseInt(0x7FFFFFFF, 16)
@@ -526,18 +526,18 @@ class Ticrypto {
* @param {String} secword
* @param {Object} option
* @return {Object}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static secword2account (secword, { coin, pass, path, tool, hasher } = {}) {
static secword_to_account ({ secword, coin, pass, pathSeed, path, tool, hasher } = {}) {
// account 比 keypair 多了 address 字段。
coin = coin?.toUpperCase() || my.COIN
let kp = this.secword2keypair(secword, { coin, pass, path, tool, hasher })
let kp = this.secword_to_keypair({ secword, coin, pass, pathSeed, path, tool, hasher })
if (kp) {
if (coin === 'ETH') {
let uncompressedPubkey = this.decompressPubkey(kp.pubkey)
kp.address = this.pubkey2address(uncompressedPubkey, { coin: 'ETH' })
let uncompressedPubkey = this.decompress_pubkey(kp.pubkey)
kp.address = this.pubkey_to_address({ pubkey: uncompressedPubkey, coin: 'ETH' })
} else {
kp.address = this.pubkey2address(kp.pubkey, { coin })
kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin })
}
return kp
}
@@ -551,17 +551,17 @@ class Ticrypto {
* @param {String} secword
* @param {Object} option
* @return {String} address
* @memberof Ticrypto
* @memberof TicCrypto
*/
static secword2address (secword, { coin, world, pass, path, tool, hasher } = {}) {
static secword_to_address ({ secword, coin, world, pass, pathSeed, path, tool, hasher } = {}) {
coin = coin?.toUpperCase() || my.COIN
let kp = this.secword2keypair(secword, { coin, pass, path, tool, hasher })
let kp = this.secword_to_keypair({ secword, coin, pass, pathSeed, path, tool, hasher })
if (kp) {
let address
if (coin === 'ETH') {
address = this.pubkey2address(this.decompressPubkey(kp.pubkey), { coin: 'ETH', world })
address = this.pubkey_to_address({ pubkey: this.decompress_pubkey(kp.pubkey), coin: 'ETH', world })
} else {
address = this.pubkey2address(kp.pubkey, { coin, world })
address = this.pubkey_to_address({ pubkey: kp.pubkey, coin, world })
}
return address
}
@@ -575,10 +575,10 @@ class Ticrypto {
* @param {*} seckey
* @param {*} [option={}]
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static seckey2pubkey (seckey, { curve, compress } = {}) {
if (this.isSeckey(seckey) && seckey.length === 64) {
static seckey_to_pubkey ({ seckey, curve, compress } = {}) {
if (this.is_seckey(seckey) && seckey.length === 64) {
// 只能用于32字节的私钥BTC, ETH)。也就是不能用于 TIC 的私钥。
curve = my.CURVE_LIST.includes(curve) ? curve : my.CURVE // 默认为 secp256k1
// return new crypto.createECDH(curve).setPrivateKey(seckey,'hex').getPublicKey('hex', compress===false?'uncompressed':'compressed') // ecdh.getPublicKey(不加参数) 默认为 'compressed'。用 HBuilderX 2.6.4 打包成ios或安卓 app 后 setPrivateKey() 报错TypeError: null is not an object (evaluating 'this.rand.getBytes')
@@ -592,7 +592,7 @@ class Ticrypto {
// return ecc.getPublicCompressed(this.hex_to_buf(seckey)).toString('hex')
// }
// 注意Buffer.from(nacl.box.keyPair.fromSecretKey(Buffer.from(seckey,'hex')).publicKey).toString('hex') 得到的公钥与上面的不同
} else if (this.isSeckey(seckey) && seckey.length === 128) {
} else if (this.is_seckey(seckey) && seckey.length === 128) {
// 用于64字节=128 hex的 TIC 私钥
let keypair = nacl.sign.keyPair.fromSecretKey(Buffer.from(seckey, 'hex'))
return Buffer.from(keypair.publicKey).toString('hex') // 测试过 不能直接keypair.publicKey.toString('hex')不是buffer类型
@@ -607,19 +607,19 @@ class Ticrypto {
* @param {*} seckey
* @param {*} option
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static seckey2address (seckey, { coin, world } = {}) {
static seckey_to_address ({ seckey, coin, world } = {}) {
coin = coin?.toUpperCase() || my.COIN
if (this.isSeckey(seckey)) {
if (this.is_seckey(seckey)) {
/** @type {*} */
let pubkey
if (coin === 'ETH') {
pubkey = this.seckey2pubkey(seckey, { compress: false })
return this.pubkey2address(pubkey, { coin, world })
pubkey = this.seckey_to_pubkey({ seckey, compress: false })
return this.pubkey_to_address({ pubkey: pubkey, coin, world })
} else {
pubkey = this.seckey2pubkey(seckey, { compress: true })
return this.pubkey2address(pubkey, { coin, world })
pubkey = this.seckey_to_pubkey({ seckey, compress: true })
return this.pubkey_to_address({ pubkey: pubkey, coin, world })
}
}
return null
@@ -632,17 +632,17 @@ class Ticrypto {
* @param {*} pubkey
* @param {*} [{ coin }={}]
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
* position 就是通常所说的 PubKeyHash出现在比特币交易的锁定脚本里
*/
static pubkey2position (pubkey, { coin } = {}) {
static pubkey_to_position ({ pubkey, coin } = {}) {
// tic, btc, eth 的 position 都是 20节=40字符的。
coin = coin?.toUpperCase() || my.COIN
if (this.isPubkey(pubkey)) {
if (this.is_pubkey({ pubkey })) {
if (coin === 'ETH') {
// 注意必须要用非压缩的64字节的公钥的buffer并去掉开头的 04。
if (pubkey.length === 66) {
pubkey = this.decompressPubkey(pubkey)
pubkey = this.decompress_pubkey(pubkey)
}
return keccak('keccak256')
.update(Buffer.from(pubkey.slice(2), 'hex'))
@@ -670,9 +670,9 @@ class Ticrypto {
* @param {*} position
* @param {*} [{ coin, world }={}]
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static position2address (position, { coin, world } = {}) {
static position_to_address ({ position, coin, world } = {}) {
if (!/^[\da-fA-F]{40}$/.test(position)) return null // 不论 tic, btc, eth其 position 都是 40字符的。
coin = coin?.toUpperCase() || my.COIN
let address
@@ -750,10 +750,10 @@ class Ticrypto {
*
* @static
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
* 地址和PubKeyHash(即position)之间能互相转化
*/
static address2position () {
static address_to_position () {
if (/^0x[\da-fA-F]{40}$/.test(address)) {
// ETH
// todo: 如果是大小写敏感的,进行有效性验证
@@ -782,9 +782,9 @@ class Ticrypto {
* @static
* @param {String} address
* @return {Boolean}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static isAddress (address) {
static is_chain_address ({address}) {
if (/^(0x)?[\da-fA-F]{40}$/.test(address)) {
return 'ETH'
} else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address) && address.length !== 32) {
@@ -811,12 +811,12 @@ class Ticrypto {
* @param {*} pubkey
* @param {*} [option={}]
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static pubkey2address (pubkey, { coin, world } = {}) {
static pubkey_to_address ({ pubkey, coin, world } = {}) {
// pubkey 应当是string类型
coin = coin?.toUpperCase() || my.COIN
return this.position2address(this.pubkey2position(pubkey, { coin }), { coin, world })
return this.position_to_address({ position: this.pubkey_to_position({ pubkey, coin }), coin, world })
}
/**
@@ -826,23 +826,26 @@ class Ticrypto {
* @param {*} secword
* @param {*} pass
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static secword2seed (secword, pass) {
static secword_to_seed ({ secword, pass }) {
// 遵循bip39的算法。和 ether.HDNode.mnemonic2Seed 结果一样是64字节的种子。
// 注意bip39.mnemonicToSeedSync 也接受不合法的 secword只要是个string或者是 undefined/null/0/''/false这几个的结果都一样
// !!! 警告bip39.mnemonicToSeedSync 也接受不合法的 secword只要是个string或者是 undefined/null/0/''/false这几个的结果都一样
return bip39.mnemonicToSeedSync(secword, pass).toString('hex') // 结果一致与 new BitcoreMnemonic(secword).toSeed(pass).toString('hex') 或 ethers.HDNode.mnemonic2Seed(secword)。
}
/**
* 生成随机的助记词
* 1) 生成 128、160、192、224、256 位的随机墒
* 2sha256 取前 墒长度/32 位作为校验和,即可为 4、5、6、7、8 位
* 3在2048=2^11个词的表中每11位指向一个词共可生成 (128+4)/11=12, (160+5)/11=15, (192+6)/11=18, (224+7)/11=21, (256+8)/11=24 个词
*
* @static
* @param {string} [lang='english']
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static randomSecword (lang = 'english') {
static randomize_secword ({ lang = 'english', wordCount = 12 } = {}) {
// accepts case-insensitive lang, such as 'chinese, cn, tw, en'
//// for BitcoreMnemonic
// lang=lang?.toUpperCase()
@@ -851,6 +854,8 @@ class Ticrypto {
// return new BitcoreMnemonic(BitcoreMnemonic.Words[language]).phrase
// for bip39
const bitLength = { 12: 128, 15: 160, 18: 192, 21: 224, 24: 256 }[wordCount] || 128
const langMap = {
zhcn: 'chinese_simplified',
zhtw: 'chinese_traditional',
@@ -868,14 +873,13 @@ class Ticrypto {
langMap.it = langMap.italy = langMap.itit
langMap.ko = langMap.kr = langMap.korean = langMap.kokr
langMap.ja = langMap.jp = langMap.japan = langMap.jajp
let language = 'english'
if (typeof lang === 'string') {
lang = lang.toLowerCase()
language = langMap[lang] || (bip39.wordlists[lang] ? lang : 'english')
}
bip39.setDefaultWordlist(language)
return bip39.generateMnemonic()
// bip39.setDefaultWordlist(language)
return bip39.generateMnemonic(bitLength, undefined, bip39.wordlists[language]) // 内部使用 crypto.randomBytes 来获取随机墒
}
/**
@@ -884,9 +888,9 @@ class Ticrypto {
* @static
* @param {*} [option={}]
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static randomSeckey ({ coin, tool } = {}) {
static randomize_seckey ({ coin, tool } = {}) {
// 跳过 secword 直接产生随机密钥
if (tool === 'nacl') {
return crypto.randomBytes(64).toString('hex') // Buffer.from(nacl.sign.keyPair().secretKey).toString('hex') // 64字节
@@ -901,9 +905,9 @@ class Ticrypto {
* @static
* @param {*} [option={}]
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static randomKeypair ({ tool, purpose } = {}) {
static randomize_keypair ({ tool, purpose } = {}) {
let kp
if (tool === 'nacl') {
if (purpose === 'encrypt') {
@@ -916,8 +920,8 @@ class Ticrypto {
pubkey: Buffer.from(kp.publicKey).toString('hex'),
}
} else {
let seckey = this.randomSeckey()
let pubkey = this.seckey2pubkey(seckey)
let seckey = this.randomize_seckey()
let pubkey = this.seckey_to_pubkey({ seckey })
return {
seckey,
pubkey,
@@ -931,11 +935,11 @@ class Ticrypto {
* @static
* @param {*} [option={}]
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static randomAccount ({ lang, coin, pass, path, tool, hasher } = {}) {
let secword = this.randomSecword(lang)
return this.secword2account(secword, { coin, pass, path, tool, hasher })
static randomize_account ({ lang, wordCount, coin, pass, pathSeed, path, tool, hasher } = {}) {
let secword = this.randomize_secword({ lang, wordCount })
return this.secword_to_account({ secword, coin, pass, pathSeed, path, tool, hasher })
}
/**
@@ -945,11 +949,10 @@ class Ticrypto {
* @param {number} [length=6]
* @param {*} alphabet
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static randomString (length = 6, alphabet) {
static randomize_string ({ length = 6, alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$%^&*@' } = {}) {
// 长度为 length字母表为 alphabet 的随机字符串
alphabet = alphabet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$%^&*@'
var text = ''
for (var i = 0; i < length; i++) {
text += alphabet.charAt(Math.floor(Math.random() * alphabet.length))
@@ -963,9 +966,9 @@ class Ticrypto {
* @static
* @param {*} [{ length, min, max }={}]
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static randomNumber ({ length, min, max } = {}) {
static randomize_number ({ length, min, max } = {}) {
// 长度为 length 的随机数字,或者 (min||0) <= num < max
var num = 0
if (typeof length === 'number' && length > 0) {
@@ -989,7 +992,7 @@ class Ticrypto {
* @param {*} targetLength
* @param {*} symbol
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static padStart (string, targetLength, symbol) {
// 2020-03: 发现在浏览器里,还不支持 string.padStart(),只好自己写个暂代。
@@ -1004,9 +1007,9 @@ class Ticrypto {
* 生成 uuid
*
* @static
* @memberof Ticrypto
* @memberof TicCrypto
*/
static randomUuid () {
static randomize_uuid () {
return uuid.v4()
}
@@ -1017,9 +1020,9 @@ class Ticrypto {
* @param {*} hashList
* @param {*} [option={}]
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static getMerkleHash (hashList, { output, hasher } = {}) {
static get_merkle_hash ({ hashList, output, hasher } = {}) {
// merkle算法略有难度暂时用最简单的hash代替
if (Array.isArray(hashList)) {
myhasher = crypto.createHash(my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER)
@@ -1035,14 +1038,14 @@ class Ticrypto {
* 获取梅克根
*
* @static
* @param {*} todoHashList
* @param {*} hashList
* @param {*} option
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static getMerkleRoot (todoHashList) {
static get_merkle_root ({ hashList } = {}) {
//深拷贝传入数组,防止引用对象被改变
let hashList = [...todoHashList]
hashList = [...hashList]
if (!Array.isArray(hashList)) return null
var border = hashList.length
if (border == 0) return this.hash('')
@@ -1075,11 +1078,11 @@ class Ticrypto {
* @param {*} hash
* @param {*} sig
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static distanceSig (hash, sig) {
static hash_to_sig_distance ({ hash, sig } = {}) {
// hash为64hex字符sig为128hex字符。返回用hex表达的距离。
if (this.isSignature(sig) && this.isHash(hash)) {
if (this.is_signature(sig) && this.is_hash({ hash })) {
var hashSig = this.hash(sig) // 把签名也转成32字节的哈希同样长度方便比较
return new BigInt(hash, 16)
.subtract(new BigInt(hashSig, 16))
@@ -1097,14 +1100,14 @@ class Ticrypto {
* @param {*} sig1
* @param {*} sig2
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static compareSig (hash, sig1, sig2) {
static compare_signatures ({ hash, sig1, sig2 } = {}) {
// 返回距离hash更近的sig
if (this.isHash(hash)) {
if (this.isSignature(sig2) && this.isSignature(sig1)) {
var dis1 = this.distanceSig(hash, sig1)
var dis2 = this.distanceSig(hash, sig2)
if (this.is_hash({ hash })) {
if (this.is_signature(sig2) && this.is_signature(sig1)) {
var dis1 = this.hash_to_sig_distance({ hash, sig: sig1 })
var dis2 = this.hash_to_sig_distance({ hash, sig: sig2 })
if (dis1 < dis2) {
return sig1
} else if (dis1 > dis2) {
@@ -1113,10 +1116,10 @@ class Ticrypto {
// 如果极其巧合的距离相等,也可能是一个在左、一个在右,那就按 signature 本身的字符串排序来比较。
return sig1 < sig2 ? sig1 : sig1 === sig2 ? sig1 : sig2
}
} else if (this.isSignature(sig2)) {
} else if (this.is_signature(sig2)) {
// 允许其中一个signature是非法的例如undefined
return sig2
} else if (this.isSignature(sig1)) {
} else if (this.is_signature(sig1)) {
return sig1
}
}
@@ -1130,13 +1133,13 @@ class Ticrypto {
* @param {*} hash
* @param {*} sigList
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static sortSigList (hash, sigList) {
if (Array.isArray(sigList) && this.isHash(hash)) {
static sort_sig_list ({ hash, sigList } = {}) {
if (Array.isArray(sigList) && this.is_hash({ hash })) {
sigList.sort(function (sig1, sig2) {
if (this.isSignature(sig1) && this.isSignature(sig2)) {
var winner = this.compareSig(hash, sig1, sig2)
if (this.is_signature(sig1) && this.is_signature(sig2)) {
var winner = this.compare_signatures({ hash, sig1, sig2 })
if (sig1 === sig2) return 0
else if (winner === sig1) return -1
else if (winner === sig2) return 1
@@ -1189,7 +1192,7 @@ class Ticrypto {
* @param {*} prikey
* @param {*} signType
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static rsaSign (string2Sign, prikey, signType) {
signType = signType || 'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more
@@ -1206,7 +1209,7 @@ class Ticrypto {
* @param {*} pubkey
* @param {*} signType
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static rsaVerify (string2Verify, signature, pubkey, signType) {
signType = signType || 'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more
@@ -1220,7 +1223,7 @@ class Ticrypto {
* @static
* @param {*} buffer
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static buf_to_hex (buffer) {
// buffer is an ArrayBuffer
@@ -1233,7 +1236,7 @@ class Ticrypto {
* @static
* @param {*} hex
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static hex_to_buf (hex) {
return new Uint8Array(
@@ -1249,7 +1252,7 @@ class Ticrypto {
* @static
* @param {*} hex
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
* 如果出现非HEX的字符从这个字符及其同Byte的另一个字符起直到末尾都会被忽略掉但仍然成功返回一个串。
* bs58check 和 bs58 可接受string, Buffer, ArrayBuffer, Array (包括空字符串'', 各种内容的数组例如包含 undefined{...},等等);
* 不可接受 undefined, null, {...}, 等等,会返回 exception
@@ -1276,7 +1279,7 @@ class Ticrypto {
* @static
* @param {*} box
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static b58c_to_hex (box) {
try {
@@ -1319,7 +1322,7 @@ class Ticrypto {
* @static
* @param {*} hex
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static hex_to_b64t (hex) {
if (/^[0-9a-fA-F]+$/.test(hex)) {
@@ -1334,7 +1337,7 @@ class Ticrypto {
* @static
* @param {*} b64t
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static b64t_to_hex (b64t) {
if (/^[0-9a-zA-Z\._]+$/.test(b64t)) {
@@ -1375,7 +1378,7 @@ class Ticrypto {
* @static
* @param {*} hex
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static hex_to_eip55 (hex) {
if (/^(0x)?[\da-fA-F]+$/.test(hex)) {
@@ -1402,9 +1405,9 @@ class Ticrypto {
* @static
* @param {*} uncompressed
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static compressPubkey (uncompressed) {
static compress_pubkey (uncompressed) {
// test: https://iancoleman.io/bitcoin-key-compression/
// compress: https://hacpai.com/article/1550844562914
// 把 04xy 的非压缩公钥 转成 02x 或 03x 的压缩公钥
@@ -1415,7 +1418,7 @@ class Ticrypto {
} else {
compressed = '02' + x // y为偶数=>前缀02
}
if (this.decompressPubkey(compressed) === uncompressed) {
if (this.decompress_pubkey(compressed) === uncompressed) {
return compressed
}
return null // 非压缩公钥有错误。
@@ -1427,9 +1430,9 @@ class Ticrypto {
* @static
* @param {*} compressed
* @return {*}
* @memberof Ticrypto
* @memberof TicCrypto
*/
static decompressPubkey (compressed) {
static decompress_pubkey (compressed) {
// uncompress: https://stackoverflow.com/questions/17171542/algorithm-for-elliptic-curve-point-compression/53478265#53478265
// https://en.bitcoin.it/wiki/Secp256k1
// 把 02x 或 03x 的压缩公钥 转成 04xy 的非压缩公钥
@@ -1512,4 +1515,4 @@ class Ticrypto {
}
// 必须单独写 module.exports不要和类定义写在一起否则会导致 jsdoc 解析不到类内文档。
module.exports = Ticrypto
module.exports = TicCrypto