From c494dd51de38bdcec2bb6bac64db31ba8a60cfef Mon Sep 17 00:00:00 2001 From: Luk Lu Date: Tue, 18 Feb 2020 12:25:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=B8=80=E4=BA=9B=E5=BA=93?= =?UTF-8?q?=E7=9A=84=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.js | 85 ++++++++++++++++++++++++++++++---------------------- package.json | 6 ++-- 2 files changed, 53 insertions(+), 38 deletions(-) diff --git a/index.js b/index.js index 273db96..86c425d 100644 --- a/index.js +++ b/index.js @@ -26,7 +26,7 @@ my.COIN_LIST=['TIC','BTC','ETH'] my.CHAINNET='mainnet' // 默认的链网 module.exports = { - hash:function(data, option){ // data can be anything, but converts to string or remains be Buffer/TypedArray/DataView + hash(data, option){ // data can be anything, but converts to string or remains be Buffer/TypedArray/DataView if (this.isHashable(data)) { option=option||{} if (typeof(data)!=='string' && !(data instanceof Buffer) && !(data instanceof DataView)) @@ -41,7 +41,7 @@ module.exports = { return null } , - isHashable:function(data, option){ + isHashable(data, option){ option=option||{} if (option.strict) { return data && typeof(data)!=='boolean' && data!==Infinity // 允许大多数数据,除了空值、布尔值、无限数 @@ -49,7 +49,7 @@ module.exports = { return typeof(data)!=='undefined' // 允许一切数据,除非 undefined } , - isHash:function(hash, option){ + isHash(hash, option){ option=option||{} option.hasher=my.HASHER_LIST.indexOf(option.hasher)>=0?option.hasher:my.HASHER switch(option.hasher){ @@ -61,7 +61,7 @@ module.exports = { return false } , - encrypt: function(data, pwd, option){ + encrypt(data, pwd, option){ if (this.isHashable(data) && typeof(pwd)==='string') { option=option||{} let inputEncoding=my.INPUT_LIST.indexOf(option.input)>=0?option.input:my.INPUT // 'utf8' by default, 'ascii', 'latin1' for string or ignored for Buffer/TypedArray/DataView @@ -78,7 +78,7 @@ module.exports = { return null } , - decrypt: function(data, pwd, option){ // data 应当是 encrypt 输出的数据类型 + decrypt(data, pwd, option){ // data 应当是 encrypt 输出的数据类型 if (data && (typeof(data)==='string' || data instanceof Buffer) && typeof(pwd)==='string') { option=option||{} let inputEncoding=my.OUTPUT_LIST.indexOf(option.input)>=0?option.input:my.OUTPUT // input (=output of encrypt) could be 'latin1', 'base64', 'hex' by default for string or ignored for Buffer @@ -100,7 +100,7 @@ module.exports = { return null } , - sign: function(data, seckey, option) { // data can be string or buffer or object, results are the same + sign(data, seckey, option) { // data can be string or buffer or object, results are the same if (this.isHashable(data) && this.isSeckey(seckey)) { option=option||{} @@ -120,11 +120,11 @@ module.exports = { return null } , - isSignature:function(signature){ + isSignature(signature){ return /^[a-fA-F0-9]{128}$/.test(signature) } , - verify: function (data, signature, pubkey, option) { // data could be anything, but converts to string or remains be Buffer/TypedArray/DataView + verify (data, signature, pubkey, option) { // data could be anything, but converts to string or remains be Buffer/TypedArray/DataView if (this.isHashable(data) && this.isSignature(signature) && this.isPubkey(pubkey)){ option=option||{} option.output='buf' // 哈希必须输出为 buffer @@ -137,7 +137,7 @@ module.exports = { return null } , - pass2keypair:function(pass, option){ // 如果使用其他机制,例如密码、随机数,不使用secword,也可生成keypair + pass2keypair(pass, option){ // 如果使用其他机制,例如密码、随机数,不使用secword,也可生成keypair if (this.isHashable(pass)){ option=option||{} option.hasher=my.HASHER_LIST.indexOf(option.hasher)>=0?option.hasher:my.HASHER @@ -152,7 +152,7 @@ module.exports = { return null } , - secword2keypair: function(secword, option){ + secword2keypair(secword, option){ // option.coin 币种; // option.passphase 密码,默认为空; // option.path==='master' 生成 HD master key,不定义则默认为相应币种的第一对公私钥。 @@ -204,7 +204,7 @@ module.exports = { return null } , - secword2account:function(secword, option){ // account 比 keypair 多了 address 字段。 + secword2account(secword, option){ // account 比 keypair 多了 address 字段。 option=option||{} option.coin=my.COIN_LIST.indexOf(option.coin)>=0?option.coin:my.COIN let kp=this.secword2keypair(secword, option) @@ -215,10 +215,9 @@ module.exports = { return null } , - secword2address:function(secword, option){ + secword2address(secword, option){ option=option||{} option.coin=my.COIN_LIST.indexOf(option.coin)>=0?option.coin:my.COIN - let address let kp=this.secword2keypair(secword, option) if (kp) { return this.seckey2address(kp.seckey,option) @@ -226,13 +225,18 @@ module.exports = { return null } , - seckey2pubkey:function(seckey, option){ + seckey2pubkey(seckey, option){ option=option||{} option.coin=my.COIN_LIST.indexOf(option.coin)>=0?option.coin:my.COIN if (this.isSeckey(seckey) && seckey.length===64){ // 只能用于32字节的私钥(BTC, ETH)。也就是不能用于 TIC 的私钥。 let curve = my.CURVE_LIST.indexOf(option.curve)>=0?option.curve:my.CURVE // 默认为 secp256k1 let compress = ['compressed', 'uncompressed'].indexOf(option.compress)>=0?option.compress:'compressed' // 默认为压缩格式的公钥 return new crypto.ECDH(curve).setPrivateKey(seckey,'hex').getPublicKey('hex',compress).toString('hex') // ecdh.getPublicKey(不加参数) 默认为 'uncompressed' + // if (option.compressed==='false'){ + // return ecc.getPublic(this.hex2arrbuf(seckey)).toString('hex') + // }else{ + // return ecc.getPublicCompressed(this.hex2arrbuf(seckey)).toString('hex') + // } // 从 nodejs 10.0 开始,还有 crypto.ECDH.convertKey 方法,更直接。 // 或者 require('secp256k1').publicKeyCreate(Buffer.from(seckey, 'hex'),compress).toString('hex') // 或者 require('bitcore-lib').PublicKey.fromPrivateKey(new Btc.PrivateKey(seckey)).toString('hex') @@ -244,7 +248,7 @@ module.exports = { return null } , - seckey2address: function(seckey, option){ + seckey2address(seckey, option){ option=option||{} option.coin=my.COIN_LIST.indexOf(option.coin)>=0?option.coin:my.COIN if (this.isSeckey(seckey)){ @@ -260,28 +264,28 @@ module.exports = { return null } , - isSecword:function(secword){ + isSecword(secword){ return Secword.isValid(secword) } , - isSeckey:function(seckey){ + isSeckey(seckey){ // 比特币、以太坊的私钥:64 hex // nacl.sign 的私钥 128 hex, nacl.box 的私钥 64 hex return /^([a-fA-F0-9]{128}|[a-fA-F0-9]{64})$/.test(seckey) } , - isPubkey:function(pubkey){ + isPubkey(pubkey){ // 比特币的公钥:压缩型 '02|03' + 64 hex 或 无压缩型 '04' + 128 hex // 以太坊的公钥:'02|03' + 64 hex // nacl.sign 的公钥:64 hex return /^((02|03)?[a-fA-F0-9]{64}|04[a-fA-F0-9]{128})$/.test(pubkey) // "d2f186a630f5558ba3ede10a4dd0549da5854eab3ed28ee8534350c2535d38b0" } , - isAddress: function (address) { + isAddress (address) { return /^[m|t|d|T][123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{33}$/.test(address) // && address.length>25 && bs58check.decode(address.slice(1)) && ['A'].indexOf(address[0]>=0)) { } , - pubkey2address:function (pubkey, option) { // pubkey 应当是string类型 + pubkey2address (pubkey, option) { // pubkey 应当是string类型 option=option||{} option.coin=my.COIN_LIST.indexOf(option.coin)>=0?option.coin:my.COIN if (this.isPubkey(pubkey)) { @@ -317,20 +321,20 @@ module.exports = { return null } , - secword2seed:function(secword, pass) { // 遵循bip39的算法。和 ether.HDNode.mnemonic2Seed 结果一样,是64字节的种子。 + secword2seed(secword, pass) { // 遵循bip39的算法。和 ether.HDNode.mnemonic2Seed 结果一样,是64字节的种子。 if (Secword.isValid(secword)) { // bip39.validateMnemonic(secword)) { return new Secword(secword).toSeed(pass).toString('hex') // 结果一致于 bip39.mnemonicToSeedHex(secword) 或 ethers.HDNode.mnemonic2Seed(secword) } return null } , - randomSecword:function(lang='ENGLISH'){ // Object.keys(Secword.Words) => [ 'CHINESE', 'ENGLISH', 'FRENCH', 'ITALIAN', 'JAPANESE', 'SPANISH' ] - let language = { zhCN: 'CHINESE', enUS: 'ENGLISH', frFR: 'FRENCH', itIT: 'ITALIAN', jaJP: 'JAPANESE', esES: 'SPANISH' }[lang] + randomSecword(lang='ENGLISH'){ // Object.keys(Secword.Words) => [ 'CHINESE', 'ENGLISH', 'FRENCH', 'ITALIAN', 'JAPANESE', 'KOREAN', 'SPANISH' ] + let language = { zhCN: 'CHINESE', enUS: 'ENGLISH', frFR: 'FRENCH', itIT: 'ITALIAN', jaJP: 'JAPANESE', koKR: 'KOREAN', esES: 'SPANISH' }[lang] || (Secword.Words.hasOwnProperty(lang.toUpperCase()) ? lang.toUpperCase() : 'ENGLISH') return new Secword(Secword.Words[language]).phrase } , - randomSeckey:function(option){ + randomSeckey(option){ option=option||{} option.coin=my.COIN_LIST.indexOf(option.coin)>=0?option.coin:my.COIN if (option.coin==='TIC'){ @@ -340,7 +344,7 @@ module.exports = { } } , - randomKeypair:function(option){ + randomKeypair(option){ option=option||{} option.coin=my.COIN_LIST.indexOf(option.coin)>=0?option.coin:my.COIN let kp @@ -355,7 +359,7 @@ module.exports = { } } , - randomString:function (length=6, alphabet) { // 长度为 length,字母表为 alphabet 的随机字符串 + randomString (length=6, alphabet) { // 长度为 length,字母表为 alphabet 的随机字符串 alphabet = alphabet||"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$%^&*@" var text = '' for (var i = 0; i < length; i++) { @@ -364,7 +368,7 @@ module.exports = { return text } , - randomNumber:function(option){ // 长度为 option.length 的随机数字,或者 (option.min||0) <= num < option.max + randomNumber(option){ // 长度为 option.length 的随机数字,或者 (option.min||0) <= num < option.max option=option||{} var num=0 if (option.length>0){ @@ -385,7 +389,7 @@ module.exports = { , randomUuid:uuid.v4 , - getMerkleHash:function(hashList, option){ + getMerkleHash(hashList, option){ // merkle算法略有难度,暂时用最简单的hash代替 if(Array.isArray(hashList)){ option=option||{} @@ -399,7 +403,7 @@ module.exports = { return null } , - getMerkleRoot:function(todoHashList, option){ + getMerkleRoot(todoHashList, option){ //深拷贝传入数组,防止引用对象被改变 let hashList = [...todoHashList] if(!Array.isArray(hashList)) @@ -429,7 +433,7 @@ module.exports = { return hashList } , - distanceSig:function(hash, sig){ // hash为64hex字符,sig为128hex字符。返回用hex表达的距离。 + distanceSig(hash, sig){ // hash为64hex字符,sig为128hex字符。返回用hex表达的距离。 if (this.isSignature(sig) && this.isHash(hash)){ var hashSig=this.hash(sig) // 把签名也转成32字节的哈希,同样长度方便比较 return new BigNumber(hash,16).minus(new BigNumber(hashSig,16)).abs().toString(16) @@ -437,7 +441,7 @@ module.exports = { return null } , - compareSig:function(hash, sig1, sig2){ // 返回距离hash更近的sig + compareSig(hash, sig1, sig2){ // 返回距离hash更近的sig if (this.isHash(hash)) { if (this.isSignature(sig2) && this.isSignature(sig1)) { var dis1=this.distanceSig(hash,sig1) @@ -458,7 +462,7 @@ module.exports = { return null } , - sortSigList:function(hash, sigList) { + sortSigList(hash, sigList) { if (Array.isArray(sigList) && this.isHash(hash)){ sigList.sort(function(sig1, sig2){ if (this.isSignature(sig1) && this.isSignature(sig2)) { @@ -480,7 +484,7 @@ module.exports = { * @param $para 需要拼接的数组 * return 拼接完成以后的字符串 */ - getString2Sign: function (paramSet, converter, delimiter) { + getString2Sign (paramSet, converter, delimiter) { if (paramSet && typeof paramSet==='object') { var string2Sign = '' var converter = converter || '' @@ -504,15 +508,26 @@ module.exports = { return '' } , - rsaSign: function(string2Sign, prikey, signType){ + rsaSign(string2Sign, prikey, signType){ signType=signType||'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more let signer=crypto.createSign(signType) return encodeURIComponent(signer.update(string2Sign).sign(prikey, 'base64')) } , - rsaVerify: function(string2Verify, sign, pubkey, signType){ + rsaVerify(string2Verify, sign, pubkey, signType){ signType=signType||'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more let verifier=crypto.createVerify(signType) return verifier.update(string2Verify).verify(pubkey, sign, 'base64') } + , + arrbuf2hex(buffer) { // buffer is an ArrayBuffer + return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(''); + } + , + hex2arrbuf(hex){ + return new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function (h) { + return parseInt(h, 16) + })) // 注意,arraybuffer没有 toString('hex')功能 + } + , } \ No newline at end of file diff --git a/package.json b/package.json index cdfe8ce..309b9b8 100644 --- a/package.json +++ b/package.json @@ -3,11 +3,11 @@ "version": "0.1.0", "private": true, "dependencies": { - "bignumber.js": "^6.0.0", - "bitcore-mnemonic": "^1.5.0", + "bignumber.js": "^9.0.0", + "bitcore-mnemonic": "^8.16.0", "bs58check": "^2.1.1", "keccak": "^2.1.0", - "tweetnacl": "^1.0.0", + "tweetnacl": "^1.0.3", "uuid": "^3.3.2" }, "devDependencies": {},