u
This commit is contained in:
parent
dff0b62d64
commit
5bfd536c03
@ -213,19 +213,19 @@
|
|||||||
<mxCell id="61" value="plaintext ^ 明文" style="whiteSpace=wrap;html=1;rounded=1;fontColor=#ffffff;strokeColor=#005700;fillColor=#008a00;" parent="1" vertex="1">
|
<mxCell id="61" value="plaintext ^ 明文" style="whiteSpace=wrap;html=1;rounded=1;fontColor=#ffffff;strokeColor=#005700;fillColor=#008a00;" parent="1" vertex="1">
|
||||||
<mxGeometry x="770" y="120" width="120" height="60" as="geometry"/>
|
<mxGeometry x="770" y="120" width="120" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="111" value="seckey2pubkey" style="shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=#1ba1e2;routingCenterX=-0.5;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
<mxCell id="111" value="seckey_to_pubkey" style="shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=#1ba1e2;routingCenterX=-0.5;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||||
<mxGeometry x="680" y="650" width="290" height="30" as="geometry"/>
|
<mxGeometry x="680" y="650" width="290" height="30" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="112" value="secword2keypair" style="shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=#1ba1e2;routingCenterX=-0.5;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
<mxCell id="112" value="secword_to_keypair" style="shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=#1ba1e2;routingCenterX=-0.5;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||||
<mxGeometry x="420" y="710" width="610" height="30" as="geometry"/>
|
<mxGeometry x="420" y="710" width="610" height="30" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="113" value="pubkey2address" style="shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=#1ba1e2;routingCenterX=-0.5;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
<mxCell id="113" value="pubkey_to_address" style="shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=#1ba1e2;routingCenterX=-0.5;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||||
<mxGeometry x="970" y="650" width="630" height="30" as="geometry"/>
|
<mxGeometry x="970" y="650" width="630" height="30" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="114" value="seckey2address" style="shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=#1ba1e2;routingCenterX=-0.5;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
<mxCell id="114" value="seckey_to_address" style="shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=#1ba1e2;routingCenterX=-0.5;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||||
<mxGeometry x="680" y="730" width="920" height="30" as="geometry"/>
|
<mxGeometry x="680" y="730" width="920" height="30" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="115" value="secword2address, secword2account" style="shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=#1ba1e2;routingCenterX=-0.5;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
<mxCell id="115" value="secword_to_address, secword_to_account" style="shape=partialRectangle;whiteSpace=wrap;html=1;bottom=1;right=1;left=1;top=0;fillColor=#1ba1e2;routingCenterX=-0.5;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||||
<mxGeometry x="360" y="770" width="1240" height="30" as="geometry"/>
|
<mxGeometry x="360" y="770" width="1240" height="30" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
</root>
|
</root>
|
||||||
|
54
README.md
54
README.md
@ -32,29 +32,29 @@ npm install git+https://git.faronear.org/npm/tic-crypto#RELEASE_OR_BRANCH --save
|
|||||||
基本用法示例:
|
基本用法示例:
|
||||||
|
|
||||||
```
|
```
|
||||||
let ticrypto=require('tic-crypto') // 引用
|
let ticc=require('tic-crypto') // 引用
|
||||||
let sw=ticrypto.randomSecword() // 生成一个随机的助记词(即密语)。或者使用现成的密语。
|
let sw=ticc.randomize_secword() // 生成一个随机的助记词(即密语)。或者使用现成的密语。
|
||||||
let kp=ticrypto.secword2keypair(sw) // 把密语转换成公私钥
|
let kp=ticc.secword_to_keypair({secword:sw}) // 把密语转换成公私钥
|
||||||
let address=ticrypto.secword2address(sw) // 把密语转换成地址
|
let address=ticc.secword_to_address({secword:sw}) // 把密语转换成地址
|
||||||
```
|
```
|
||||||
|
|
||||||
## 其他
|
## 其他
|
||||||
|
|
||||||
```
|
```
|
||||||
const keyPair = crypto.generateKeyPairSync('rsa', {
|
const keyPair = crypto.generateKeyPairSync('rsa', {
|
||||||
modulusLength: 520,
|
modulusLength: 520,
|
||||||
publicKeyEncoding: {
|
publicKeyEncoding: {
|
||||||
type: 'spki',
|
type: 'spki',
|
||||||
format: 'pem'
|
format: 'pem'
|
||||||
},
|
},
|
||||||
|
|
||||||
privateKeyEncoding: {
|
privateKeyEncoding: {
|
||||||
type: 'pkcs8',
|
type: 'pkcs8',
|
||||||
format: 'pem',
|
format: 'pem',
|
||||||
cipher: 'aes-256-cbc',
|
cipher: 'aes-256-cbc',
|
||||||
passphrase: ''
|
passphrase: ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
这样生成的 keyPair.privateKey 开头是 -----BEGIN ENCRYPTED PRIVATE KEY-----
|
这样生成的 keyPair.privateKey 开头是 -----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
@ -62,19 +62,19 @@ const keyPair = crypto.generateKeyPairSync('rsa', {
|
|||||||
如果直接
|
如果直接
|
||||||
|
|
||||||
```
|
```
|
||||||
crypto.privateEncrypt(kp.privateKey, Buffer.from('sdafasfdsaf'))
|
crypto.privateEncrypt(kp.privateKey, Buffer.from('sdafasfdsaf'))
|
||||||
```
|
```
|
||||||
|
|
||||||
会报错
|
会报错
|
||||||
|
|
||||||
```
|
```
|
||||||
Uncaught TypeError: Passphrase required for encrypted key
|
Uncaught TypeError: Passphrase required for encrypted key
|
||||||
```
|
```
|
||||||
|
|
||||||
所以要这样才行
|
所以要这样才行
|
||||||
|
|
||||||
```
|
```
|
||||||
crypto.privateEncrypt({key:kp.privateKey, passphrase:''}, Buffer.from('sdafasfdsaf'))
|
crypto.privateEncrypt({key:kp.privateKey, passphrase:''}, Buffer.from('sdafasfdsaf'))
|
||||||
```
|
```
|
||||||
|
|
||||||
我从 https://www.cnblogs.com/chyingp/p/nodejs-asymmetric-enc-dec.html 抄到一个 privateKey 可以直接使用,不需要 passphrase
|
我从 https://www.cnblogs.com/chyingp/p/nodejs-asymmetric-enc-dec.html 抄到一个 privateKey 可以直接使用,不需要 passphrase
|
||||||
@ -86,14 +86,14 @@ crypto.privateEncrypt({key:kp.privateKey, passphrase:''}, Buffer.from('sdafasfds
|
|||||||
可以直接
|
可以直接
|
||||||
|
|
||||||
```
|
```
|
||||||
crypto.publicEncrypt(kp.publicKey, Buffer.from('sdafasfdsaf'))
|
crypto.publicEncrypt(kp.publicKey, Buffer.from('sdafasfdsaf'))
|
||||||
```
|
```
|
||||||
|
|
||||||
返回 Buffer。每次结果不一样
|
返回 Buffer。每次结果不一样
|
||||||
|
|
||||||
似乎 crypto 一定要 rsa 公私钥才可以用加解密,ticrypto.randomKeypair() 生成的 ecc 公私钥不行。
|
似乎 crypto 一定要 rsa 公私钥才可以用加解密,ticc.randomize_keypair() 生成的 ecc 公私钥不行。
|
||||||
|
|
||||||
而 eccrypto 和 eccrypto-js 可以用。eccrypto.generateKeyPair() 生成的和 ticrypto.randomKeypair() 一样
|
而 eccrypto 和 eccrypto-js 可以用。eccrypto.generateKeyPair() 生成的和 ticc.randomize_keypair() 一样
|
||||||
|
|
||||||
eccrypto 在 windows 上的安装有麻烦,一来需要手工安装 OpenSSL 到 c:\openssl-win64\,二来 openssl 1.1.0 起把 libeay32.lib 改名为 libcrypto.dll,而 eccrypto 需要 c:\openssl-win64\lib\libeay32.lib,会报错
|
eccrypto 在 windows 上的安装有麻烦,一来需要手工安装 OpenSSL 到 c:\openssl-win64\,二来 openssl 1.1.0 起把 libeay32.lib 改名为 libcrypto.dll,而 eccrypto 需要 c:\openssl-win64\lib\libeay32.lib,会报错
|
||||||
|
|
||||||
@ -101,9 +101,9 @@ eccrypto-js 在 devDependencies 里继承了 eccrypto,因此 npm i --productio
|
|||||||
|
|
||||||
base32 有多种字符集:[Base32 - Wikipedia](https://en.wikipedia.org/wiki/Base32)
|
base32 有多种字符集:[Base32 - Wikipedia](https://en.wikipedia.org/wiki/Base32)
|
||||||
|
|
||||||
IPFS用的是 RFC4648字符集
|
IPFS 用的是 RFC4648 字符集
|
||||||
|
|
||||||
- 从数到数符串:Number(数).toString(进制数),0x数.toString(进制数), 0b数.toString(进制数)
|
- 从数到数符串:Number(数).toString(进制数),0x 数.toString(进制数), 0b 数.toString(进制数)
|
||||||
- 从数符串到数字:parseInt(str, 进制数)
|
- 从数符串到数字:parseInt(str, 进制数)
|
||||||
- Buffer到数符串: Buffer.toString(编码方案例如'hex','base64',默认'utf8')
|
- Buffer 到数符串: Buffer.toString(编码方案例如'hex','base64',默认'utf8')
|
||||||
- 字符串到Buffer: Buffer.from(data, 编码方案如'hex','base64',默认'utf8')
|
- 字符串到 Buffer: Buffer.from(data, 编码方案如'hex','base64',默认'utf8')
|
||||||
|
289
index.js
289
index.js
@ -45,9 +45,9 @@ my.REGEXP_ALPHABET = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @class Ticrypto
|
* @class TicCrypto
|
||||||
*/
|
*/
|
||||||
class Ticrypto {
|
class TicCrypto {
|
||||||
/**
|
/**
|
||||||
* 测试输入数据是否可哈希混淆
|
* 测试输入数据是否可哈希混淆
|
||||||
*
|
*
|
||||||
@ -55,9 +55,9 @@ class Ticrypto {
|
|||||||
* @param {*} data 需要被哈希混淆的数据
|
* @param {*} data 需要被哈希混淆的数据
|
||||||
* @param {*} option 可选参数
|
* @param {*} option 可选参数
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static isHashable (data, { strict = false } = {}) {
|
static is_hashable ({ data, strict = false } = {}) {
|
||||||
if (strict) {
|
if (strict) {
|
||||||
return typeof data !== 'boolean' && data !== Infinity && data ? true : false // 允许大多数数据,除了null、''、0、布尔值、无限数。注意 data 要放在最后,否则会被 return 直接返回,而不是返回 Boolean
|
return typeof data !== 'boolean' && data !== Infinity && data ? true : false // 允许大多数数据,除了null、''、0、布尔值、无限数。注意 data 要放在最后,否则会被 return 直接返回,而不是返回 Boolean
|
||||||
}
|
}
|
||||||
@ -71,9 +71,9 @@ class Ticrypto {
|
|||||||
* @param {String} hash
|
* @param {String} hash
|
||||||
* @param {Object} option [{ hasher = my.HASHER }={}]
|
* @param {Object} option [{ hasher = my.HASHER }={}]
|
||||||
* @return {Boolean}
|
* @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)) {
|
if (my.HASHER_LIST.includes(hasher)) {
|
||||||
switch (hasher) {
|
switch (hasher) {
|
||||||
case 'sha256':
|
case 'sha256':
|
||||||
@ -97,10 +97,10 @@ class Ticrypto {
|
|||||||
* @param {String} secword
|
* @param {String} secword
|
||||||
* @param {Object} option [{ mode = 'strict' }={}]
|
* @param {Object} option [{ mode = 'strict' }={}]
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static isSecword (secword, { mode = 'strict' } = {}) {
|
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, ... 长度的合法助记词都返回 true。
|
// 注意 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词的会抛出异常,很蠢。
|
//// for bitcore-mnemonic. 注意,bitcore-mnemonic 对少于12词的会抛出异常,很蠢。
|
||||||
// if (typeof secword==='string' && 12===secword.split(/ +/).length)
|
// if (typeof secword==='string' && 12===secword.split(/ +/).length)
|
||||||
// return BitcoreMnemonic.isValid(secword)
|
// return BitcoreMnemonic.isValid(secword)
|
||||||
@ -124,9 +124,9 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {String} seckey
|
* @param {String} seckey
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static isSeckey (seckey) {
|
static is_seckey (seckey) {
|
||||||
// 比特币、以太坊的私钥:64 hex
|
// 比特币、以太坊的私钥:64 hex
|
||||||
// nacl.sign 的私钥 128 hex, nacl.box 的私钥 64 hex
|
// nacl.sign 的私钥 128 hex, nacl.box 的私钥 64 hex
|
||||||
return /^([a-fA-F0-9]{128}|[a-fA-F0-9]{64})$/.test(seckey)
|
return /^([a-fA-F0-9]{128}|[a-fA-F0-9]{64})$/.test(seckey)
|
||||||
@ -138,9 +138,9 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {String} pubkey
|
* @param {String} pubkey
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static isPubkey (pubkey) {
|
static is_pubkey ({ pubkey } = {}) {
|
||||||
// 比特币的公钥:压缩型 '02|03' + 64 hex 或 无压缩型 '04' + 128 hex
|
// 比特币的公钥:压缩型 '02|03' + 64 hex 或 无压缩型 '04' + 128 hex
|
||||||
// 以太坊的公钥:'02|03' + 64 hex
|
// 以太坊的公钥:'02|03' + 64 hex
|
||||||
// nacl.sign 的公钥:64 hex
|
// nacl.sign 的公钥:64 hex
|
||||||
@ -153,9 +153,9 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {String} signature
|
* @param {String} signature
|
||||||
* @return {Boolean}
|
* @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.
|
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 {*} data
|
||||||
* @param {option} [{ hasher = my.HASHER, salt, input = my.INPUT, output = my.OUTPUT }={}]
|
* @param {option} [{ hasher = my.HASHER, salt, input = my.INPUT, output = my.OUTPUT }={}]
|
||||||
* @return {String}
|
* @return {String}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static hash (data, { hasher = my.HASHER, salt, input = my.INPUT, output = my.OUTPUT } = {}) {
|
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
|
// 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 (typeof data !== 'string' && !(data instanceof Buffer) && !(data instanceof DataView)) data = JSON.stringify(data)
|
||||||
if (salt && typeof salt === 'string') data = data + this.hash(salt)
|
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.
|
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 {*} data
|
||||||
* @param {*} option [{ tool, keytype, key, input, output, cipher }={}]
|
* @param {*} option [{ tool, keytype, key, input, output, cipher }={}]
|
||||||
* @return {String}
|
* @return {String}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static async encrypt ({ data, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) {
|
static async encrypt ({ data, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) {
|
||||||
if (tool === 'eccrypto') {
|
if (tool === 'eccrypto') {
|
||||||
@ -213,7 +213,7 @@ class Ticrypto {
|
|||||||
return { iv: iv.toString('hex'), ciphertext } // 有 iv,显然每次结果不一样
|
return { iv: iv.toString('hex'), ciphertext } // 有 iv,显然每次结果不一样
|
||||||
}
|
}
|
||||||
} else if (keytype === 'seckey') {
|
} 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字节。
|
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') {
|
||||||
@ -230,7 +230,7 @@ class Ticrypto {
|
|||||||
* @param {*} data
|
* @param {*} data
|
||||||
* @param {Object} option [{ keytype, key, input, output, cipher, format }={}]
|
* @param {Object} option [{ keytype, key, input, output, cipher, format }={}]
|
||||||
* @return {String}
|
* @return {String}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static async decrypt ({ data = {}, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) {
|
static async decrypt ({ data = {}, tool = 'crypto', keytype = 'pwd', key, input, output, cipher } = {}) {
|
||||||
// data 应当是 encrypt 输出的数据类型
|
// data 应当是 encrypt 输出的数据类型
|
||||||
@ -261,7 +261,7 @@ class Ticrypto {
|
|||||||
return decrypted
|
return decrypted
|
||||||
}
|
}
|
||||||
} else if (keytype === 'seckey') {
|
} 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字节。
|
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。每次结果都一样。
|
return crypto.privateDecrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
|
||||||
} else if (keytype === 'pubkey') {
|
} else if (keytype === 'pubkey') {
|
||||||
@ -279,11 +279,11 @@ class Ticrypto {
|
|||||||
* @param {String} seckey
|
* @param {String} seckey
|
||||||
* @param {Object} option [option={}]
|
* @param {Object} option [option={}]
|
||||||
* @return {String}
|
* @return {String}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static async sign ({ data, seckey, tool = 'crypto', hasher }) {
|
static async sign ({ data, seckey, tool = 'crypto', hasher }) {
|
||||||
// data can be string or buffer or object, results are the same
|
// 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) {
|
if (tool === 'nacl' && seckey.length === 128) {
|
||||||
// 使用nacl的签名算法。注意,nacl.sign需要的seckey是64字节=128字符。
|
// 使用nacl的签名算法。注意,nacl.sign需要的seckey是64字节=128字符。
|
||||||
let hashBuf = this.hash(data, { output: 'buf' }) // 哈希必须输出为 buffer
|
let hashBuf = this.hash(data, { output: 'buf' }) // 哈希必须输出为 buffer
|
||||||
@ -316,11 +316,11 @@ class Ticrypto {
|
|||||||
* @param {String} pubkey
|
* @param {String} pubkey
|
||||||
* @param {Object} option [option={}]
|
* @param {Object} option [option={}]
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static async verify ({ data, signature, pubkey, tool = 'crypto', hasher }) {
|
static async verify ({ data, signature, pubkey, tool = 'crypto', hasher }) {
|
||||||
// data could be anything, but converts to string or remains be Buffer/TypedArray/DataView
|
// 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) {
|
if ('nacl' === tool && signature.length === 128) {
|
||||||
let bufHash = this.hash(data, { output: 'buf' })
|
let bufHash = this.hash(data, { output: 'buf' })
|
||||||
let bufSignature = Buffer.from(signature, 'hex')
|
let bufSignature = Buffer.from(signature, 'hex')
|
||||||
@ -357,11 +357,11 @@ class Ticrypto {
|
|||||||
* @param {String} pass
|
* @param {String} pass
|
||||||
* @param {Object} option
|
* @param {Object} option
|
||||||
* @return {Object} {pubkey, seckey, address,}
|
* @return {Object} {pubkey, seckey, address,}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static pass2keypair (pass, { hasher } = {}) {
|
static pass2keypair ({ pass, hasher } = {}) {
|
||||||
// 如果使用其他机制,例如密码、随机数,不使用secword,也可生成keypair
|
// 如果使用其他机制,例如密码、随机数,不使用secword,也可生成keypair
|
||||||
if (this.isHashable(pass)) {
|
if (this.is_hashable({ data: pass })) {
|
||||||
hasher = my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER
|
hasher = my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER
|
||||||
var hashBuf = crypto
|
var hashBuf = crypto
|
||||||
.createHash(hasher)
|
.createHash(hasher)
|
||||||
@ -383,10 +383,10 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} entropy
|
* @param {*} entropy
|
||||||
* @return {String}
|
* @return {String}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static entropy2secword (entropy) {
|
static entropy_to_secword ({ 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, ...
|
// 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.
|
return bip39.entropyToMnemonic(entropy) // results are the same for the same entropy.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,10 +396,10 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {String} secword
|
* @param {String} secword
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static secword2entropy (secword) {
|
static secword_to_entropy ({ secword } = {}) {
|
||||||
// secword could be of length 12, 15, 18, ... which outputs hex of length 32, 40, ...
|
// secword could be of length 12, 15, 18, 21, 24,which outputs hex of length 32, 40, 48, 56, 64.
|
||||||
return bip39.mnemonicToEntropy(secword) // results are the same for the same secword.
|
return bip39.mnemonicToEntropy(secword) // results are the same for the same secword.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,9 +410,9 @@ class Ticrypto {
|
|||||||
* @param {String} secword
|
* @param {String} secword
|
||||||
* @param {Object} option
|
* @param {Object} option
|
||||||
* @return {Object} {pubkey, seckey,}
|
* @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 币种;
|
// coin 币种;
|
||||||
// passphase 密码,默认为空;
|
// passphase 密码,默认为空;
|
||||||
// path==='master' 生成 HD master key,不定义则默认为相应币种的第一对公私钥。
|
// path==='master' 生成 HD master key,不定义则默认为相应币种的第一对公私钥。
|
||||||
@ -431,7 +431,7 @@ class Ticrypto {
|
|||||||
hasher = my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER
|
hasher = my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER
|
||||||
let hashBuf = crypto
|
let hashBuf = crypto
|
||||||
.createHash(hasher)
|
.createHash(hasher)
|
||||||
.update(this.secword2seed(secword, pass))
|
.update(this.secword_to_seed({ secword, pass }))
|
||||||
.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 {
|
||||||
@ -443,22 +443,22 @@ class Ticrypto {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 用 bip39 算法从 secword 到种子,再用 bip32 算法从种子到根私钥。这是比特币、以太坊的标准方式,结果一致。
|
// 用 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 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 === 'master') {
|
||||||
key = hdmaster
|
key = hdmaster
|
||||||
} else {
|
} else {
|
||||||
// 指定了路径 path 例如 "m/0/2147483647'/1" 则用 path;没有指定路径 则调用 seed2path() 来获取默认的根路径 例如 "m/44'/0'/0'/0/0" 或 "m/44'/60'/0'/0/0"
|
// 指定了路径 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.seed2path({ coin })
|
path = path || this.seed_to_path({ seed: pathSeed, coin })
|
||||||
key = hdmaster.derive(path)
|
key = hdmaster.derive(path)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
coin: coin,
|
coin,
|
||||||
secword: secword,
|
secword,
|
||||||
|
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'),
|
||||||
path,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@ -471,9 +471,9 @@ class Ticrypto {
|
|||||||
* @param {*} seed
|
* @param {*} seed
|
||||||
* @param {string} option [{ coin = my.COIN }={ coin: my.COIN }]
|
* @param {string} option [{ coin = my.COIN }={ coin: my.COIN }]
|
||||||
* @return {String} path
|
* @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,
|
// 路径规范 BIP44: m/Purpose'/Coin'/Account'/Change/Index,
|
||||||
// 但实际上 Purpose, Coin 都可任意定;' 可有可无;
|
// 但实际上 Purpose, Coin 都可任意定;' 可有可无;
|
||||||
// Account/Change/Index 最大到 parseInt(0x7FFFFFFF, 16)
|
// Account/Change/Index 最大到 parseInt(0x7FFFFFFF, 16)
|
||||||
@ -526,18 +526,18 @@ class Ticrypto {
|
|||||||
* @param {String} secword
|
* @param {String} secword
|
||||||
* @param {Object} option
|
* @param {Object} option
|
||||||
* @return {Object}
|
* @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 字段。
|
// account 比 keypair 多了 address 字段。
|
||||||
coin = coin?.toUpperCase() || my.COIN
|
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 (kp) {
|
||||||
if (coin === 'ETH') {
|
if (coin === 'ETH') {
|
||||||
let uncompressedPubkey = this.decompressPubkey(kp.pubkey)
|
let uncompressedPubkey = this.decompress_pubkey(kp.pubkey)
|
||||||
kp.address = this.pubkey2address(uncompressedPubkey, { coin: 'ETH' })
|
kp.address = this.pubkey_to_address({ pubkey: uncompressedPubkey, coin: 'ETH' })
|
||||||
} else {
|
} else {
|
||||||
kp.address = this.pubkey2address(kp.pubkey, { coin })
|
kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin })
|
||||||
}
|
}
|
||||||
return kp
|
return kp
|
||||||
}
|
}
|
||||||
@ -551,17 +551,17 @@ class Ticrypto {
|
|||||||
* @param {String} secword
|
* @param {String} secword
|
||||||
* @param {Object} option
|
* @param {Object} option
|
||||||
* @return {String} address
|
* @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
|
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 (kp) {
|
||||||
let address
|
let address
|
||||||
if (coin === 'ETH') {
|
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 {
|
} else {
|
||||||
address = this.pubkey2address(kp.pubkey, { coin, world })
|
address = this.pubkey_to_address({ pubkey: kp.pubkey, coin, world })
|
||||||
}
|
}
|
||||||
return address
|
return address
|
||||||
}
|
}
|
||||||
@ -575,10 +575,10 @@ class Ticrypto {
|
|||||||
* @param {*} seckey
|
* @param {*} seckey
|
||||||
* @param {*} [option={}]
|
* @param {*} [option={}]
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static seckey2pubkey (seckey, { curve, compress } = {}) {
|
static seckey_to_pubkey ({ seckey, curve, compress } = {}) {
|
||||||
if (this.isSeckey(seckey) && seckey.length === 64) {
|
if (this.is_seckey(seckey) && seckey.length === 64) {
|
||||||
// 只能用于32字节的私钥(BTC, ETH)。也就是不能用于 TIC 的私钥。
|
// 只能用于32字节的私钥(BTC, ETH)。也就是不能用于 TIC 的私钥。
|
||||||
curve = my.CURVE_LIST.includes(curve) ? curve : my.CURVE // 默认为 secp256k1
|
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')
|
// 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')
|
// return ecc.getPublicCompressed(this.hex_to_buf(seckey)).toString('hex')
|
||||||
// }
|
// }
|
||||||
// 注意,Buffer.from(nacl.box.keyPair.fromSecretKey(Buffer.from(seckey,'hex')).publicKey).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 私钥
|
// 用于64字节=128 hex的 TIC 私钥
|
||||||
let keypair = nacl.sign.keyPair.fromSecretKey(Buffer.from(seckey, 'hex'))
|
let keypair = nacl.sign.keyPair.fromSecretKey(Buffer.from(seckey, 'hex'))
|
||||||
return Buffer.from(keypair.publicKey).toString('hex') // 测试过 不能直接keypair.publicKey.toString('hex'),不是buffer类型
|
return Buffer.from(keypair.publicKey).toString('hex') // 测试过 不能直接keypair.publicKey.toString('hex'),不是buffer类型
|
||||||
@ -607,19 +607,19 @@ class Ticrypto {
|
|||||||
* @param {*} seckey
|
* @param {*} seckey
|
||||||
* @param {*} option
|
* @param {*} option
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static seckey2address (seckey, { coin, world } = {}) {
|
static seckey_to_address ({ seckey, coin, world } = {}) {
|
||||||
coin = coin?.toUpperCase() || my.COIN
|
coin = coin?.toUpperCase() || my.COIN
|
||||||
if (this.isSeckey(seckey)) {
|
if (this.is_seckey(seckey)) {
|
||||||
/** @type {*} */
|
/** @type {*} */
|
||||||
let pubkey
|
let pubkey
|
||||||
if (coin === 'ETH') {
|
if (coin === 'ETH') {
|
||||||
pubkey = this.seckey2pubkey(seckey, { compress: false })
|
pubkey = this.seckey_to_pubkey({ seckey, compress: false })
|
||||||
return this.pubkey2address(pubkey, { coin, world })
|
return this.pubkey_to_address({ pubkey: pubkey, coin, world })
|
||||||
} else {
|
} else {
|
||||||
pubkey = this.seckey2pubkey(seckey, { compress: true })
|
pubkey = this.seckey_to_pubkey({ seckey, compress: true })
|
||||||
return this.pubkey2address(pubkey, { coin, world })
|
return this.pubkey_to_address({ pubkey: pubkey, coin, world })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@ -632,17 +632,17 @@ class Ticrypto {
|
|||||||
* @param {*} pubkey
|
* @param {*} pubkey
|
||||||
* @param {*} [{ coin }={}]
|
* @param {*} [{ coin }={}]
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
* position 就是通常所说的 PubKeyHash,出现在比特币交易的锁定脚本里
|
* position 就是通常所说的 PubKeyHash,出现在比特币交易的锁定脚本里
|
||||||
*/
|
*/
|
||||||
static pubkey2position (pubkey, { coin } = {}) {
|
static pubkey_to_position ({ pubkey, coin } = {}) {
|
||||||
// tic, btc, eth 的 position 都是 20节=40字符的。
|
// tic, btc, eth 的 position 都是 20节=40字符的。
|
||||||
coin = coin?.toUpperCase() || my.COIN
|
coin = coin?.toUpperCase() || my.COIN
|
||||||
if (this.isPubkey(pubkey)) {
|
if (this.is_pubkey({ pubkey })) {
|
||||||
if (coin === 'ETH') {
|
if (coin === 'ETH') {
|
||||||
// 注意,必须要用非压缩的64字节的公钥的buffer,并去掉开头的 04。
|
// 注意,必须要用非压缩的64字节的公钥的buffer,并去掉开头的 04。
|
||||||
if (pubkey.length === 66) {
|
if (pubkey.length === 66) {
|
||||||
pubkey = this.decompressPubkey(pubkey)
|
pubkey = this.decompress_pubkey(pubkey)
|
||||||
}
|
}
|
||||||
return keccak('keccak256')
|
return keccak('keccak256')
|
||||||
.update(Buffer.from(pubkey.slice(2), 'hex'))
|
.update(Buffer.from(pubkey.slice(2), 'hex'))
|
||||||
@ -670,9 +670,9 @@ class Ticrypto {
|
|||||||
* @param {*} position
|
* @param {*} position
|
||||||
* @param {*} [{ coin, world }={}]
|
* @param {*} [{ coin, world }={}]
|
||||||
* @return {*}
|
* @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字符的。
|
if (!/^[\da-fA-F]{40}$/.test(position)) return null // 不论 tic, btc, eth,其 position 都是 40字符的。
|
||||||
coin = coin?.toUpperCase() || my.COIN
|
coin = coin?.toUpperCase() || my.COIN
|
||||||
let address
|
let address
|
||||||
@ -750,10 +750,10 @@ class Ticrypto {
|
|||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
* 地址和PubKeyHash(即position)之间能互相转化
|
* 地址和PubKeyHash(即position)之间能互相转化
|
||||||
*/
|
*/
|
||||||
static address2position () {
|
static address_to_position () {
|
||||||
if (/^0x[\da-fA-F]{40}$/.test(address)) {
|
if (/^0x[\da-fA-F]{40}$/.test(address)) {
|
||||||
// ETH
|
// ETH
|
||||||
// todo: 如果是大小写敏感的,进行有效性验证
|
// todo: 如果是大小写敏感的,进行有效性验证
|
||||||
@ -782,9 +782,9 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {String} address
|
* @param {String} address
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static isAddress (address) {
|
static is_chain_address ({address}) {
|
||||||
if (/^(0x)?[\da-fA-F]{40}$/.test(address)) {
|
if (/^(0x)?[\da-fA-F]{40}$/.test(address)) {
|
||||||
return 'ETH'
|
return 'ETH'
|
||||||
} else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address) && address.length !== 32) {
|
} else if (/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{26,34}$/.test(address) && address.length !== 32) {
|
||||||
@ -811,12 +811,12 @@ class Ticrypto {
|
|||||||
* @param {*} pubkey
|
* @param {*} pubkey
|
||||||
* @param {*} [option={}]
|
* @param {*} [option={}]
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static pubkey2address (pubkey, { coin, world } = {}) {
|
static pubkey_to_address ({ pubkey, coin, world } = {}) {
|
||||||
// pubkey 应当是string类型
|
// pubkey 应当是string类型
|
||||||
coin = coin?.toUpperCase() || my.COIN
|
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 {*} secword
|
||||||
* @param {*} pass
|
* @param {*} pass
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static secword2seed (secword, pass) {
|
static secword_to_seed ({ secword, pass }) {
|
||||||
// 遵循bip39的算法。和 ether.HDNode.mnemonic2Seed 结果一样,是64字节的种子。
|
// 遵循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)。
|
return bip39.mnemonicToSeedSync(secword, pass).toString('hex') // 结果一致与 new BitcoreMnemonic(secword).toSeed(pass).toString('hex') 或 ethers.HDNode.mnemonic2Seed(secword)。
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成随机的助记词
|
* 生成随机的助记词
|
||||||
|
* 1) 生成 128、160、192、224、256 位的随机墒
|
||||||
|
* 2)sha256 取前 墒长度/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
|
* @static
|
||||||
* @param {string} [lang='english']
|
* @param {string} [lang='english']
|
||||||
* @return {*}
|
* @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'
|
// accepts case-insensitive lang, such as 'chinese, cn, tw, en'
|
||||||
//// for BitcoreMnemonic
|
//// for BitcoreMnemonic
|
||||||
// lang=lang?.toUpperCase()
|
// lang=lang?.toUpperCase()
|
||||||
@ -851,6 +854,8 @@ class Ticrypto {
|
|||||||
// return new BitcoreMnemonic(BitcoreMnemonic.Words[language]).phrase
|
// return new BitcoreMnemonic(BitcoreMnemonic.Words[language]).phrase
|
||||||
|
|
||||||
// for bip39
|
// for bip39
|
||||||
|
const bitLength = { 12: 128, 15: 160, 18: 192, 21: 224, 24: 256 }[wordCount] || 128
|
||||||
|
|
||||||
const langMap = {
|
const langMap = {
|
||||||
zhcn: 'chinese_simplified',
|
zhcn: 'chinese_simplified',
|
||||||
zhtw: 'chinese_traditional',
|
zhtw: 'chinese_traditional',
|
||||||
@ -868,14 +873,13 @@ class Ticrypto {
|
|||||||
langMap.it = langMap.italy = langMap.itit
|
langMap.it = langMap.italy = langMap.itit
|
||||||
langMap.ko = langMap.kr = langMap.korean = langMap.kokr
|
langMap.ko = langMap.kr = langMap.korean = langMap.kokr
|
||||||
langMap.ja = langMap.jp = langMap.japan = langMap.jajp
|
langMap.ja = langMap.jp = langMap.japan = langMap.jajp
|
||||||
|
|
||||||
let language = 'english'
|
let language = 'english'
|
||||||
if (typeof lang === 'string') {
|
if (typeof lang === 'string') {
|
||||||
lang = lang.toLowerCase()
|
lang = lang.toLowerCase()
|
||||||
language = langMap[lang] || (bip39.wordlists[lang] ? lang : 'english')
|
language = langMap[lang] || (bip39.wordlists[lang] ? lang : 'english')
|
||||||
}
|
}
|
||||||
bip39.setDefaultWordlist(language)
|
// bip39.setDefaultWordlist(language)
|
||||||
return bip39.generateMnemonic()
|
return bip39.generateMnemonic(bitLength, undefined, bip39.wordlists[language]) // 内部使用 crypto.randomBytes 来获取随机墒
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -884,9 +888,9 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} [option={}]
|
* @param {*} [option={}]
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static randomSeckey ({ coin, tool } = {}) {
|
static randomize_seckey ({ coin, tool } = {}) {
|
||||||
// 跳过 secword 直接产生随机密钥
|
// 跳过 secword 直接产生随机密钥
|
||||||
if (tool === 'nacl') {
|
if (tool === 'nacl') {
|
||||||
return crypto.randomBytes(64).toString('hex') // Buffer.from(nacl.sign.keyPair().secretKey).toString('hex') // 64字节
|
return crypto.randomBytes(64).toString('hex') // Buffer.from(nacl.sign.keyPair().secretKey).toString('hex') // 64字节
|
||||||
@ -901,9 +905,9 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} [option={}]
|
* @param {*} [option={}]
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static randomKeypair ({ tool, purpose } = {}) {
|
static randomize_keypair ({ tool, purpose } = {}) {
|
||||||
let kp
|
let kp
|
||||||
if (tool === 'nacl') {
|
if (tool === 'nacl') {
|
||||||
if (purpose === 'encrypt') {
|
if (purpose === 'encrypt') {
|
||||||
@ -916,8 +920,8 @@ class Ticrypto {
|
|||||||
pubkey: Buffer.from(kp.publicKey).toString('hex'),
|
pubkey: Buffer.from(kp.publicKey).toString('hex'),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let seckey = this.randomSeckey()
|
let seckey = this.randomize_seckey()
|
||||||
let pubkey = this.seckey2pubkey(seckey)
|
let pubkey = this.seckey_to_pubkey({ seckey })
|
||||||
return {
|
return {
|
||||||
seckey,
|
seckey,
|
||||||
pubkey,
|
pubkey,
|
||||||
@ -931,11 +935,11 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} [option={}]
|
* @param {*} [option={}]
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static randomAccount ({ lang, coin, pass, path, tool, hasher } = {}) {
|
static randomize_account ({ lang, wordCount, coin, pass, pathSeed, path, tool, hasher } = {}) {
|
||||||
let secword = this.randomSecword(lang)
|
let secword = this.randomize_secword({ lang, wordCount })
|
||||||
return this.secword2account(secword, { coin, pass, path, tool, hasher })
|
return this.secword_to_account({ secword, coin, pass, pathSeed, path, tool, hasher })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -945,11 +949,10 @@ class Ticrypto {
|
|||||||
* @param {number} [length=6]
|
* @param {number} [length=6]
|
||||||
* @param {*} alphabet
|
* @param {*} alphabet
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static randomString (length = 6, alphabet) {
|
static randomize_string ({ length = 6, alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$%^&*@' } = {}) {
|
||||||
// 长度为 length,字母表为 alphabet 的随机字符串
|
// 长度为 length,字母表为 alphabet 的随机字符串
|
||||||
alphabet = alphabet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#$%^&*@'
|
|
||||||
var text = ''
|
var text = ''
|
||||||
for (var i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
text += alphabet.charAt(Math.floor(Math.random() * alphabet.length))
|
text += alphabet.charAt(Math.floor(Math.random() * alphabet.length))
|
||||||
@ -963,9 +966,9 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} [{ length, min, max }={}]
|
* @param {*} [{ length, min, max }={}]
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static randomNumber ({ length, min, max } = {}) {
|
static randomize_number ({ length, min, max } = {}) {
|
||||||
// 长度为 length 的随机数字,或者 (min||0) <= num < max
|
// 长度为 length 的随机数字,或者 (min||0) <= num < max
|
||||||
var num = 0
|
var num = 0
|
||||||
if (typeof length === 'number' && length > 0) {
|
if (typeof length === 'number' && length > 0) {
|
||||||
@ -989,7 +992,7 @@ class Ticrypto {
|
|||||||
* @param {*} targetLength
|
* @param {*} targetLength
|
||||||
* @param {*} symbol
|
* @param {*} symbol
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static padStart (string, targetLength, symbol) {
|
static padStart (string, targetLength, symbol) {
|
||||||
// 2020-03: 发现在浏览器里,还不支持 string.padStart(),只好自己写个暂代。
|
// 2020-03: 发现在浏览器里,还不支持 string.padStart(),只好自己写个暂代。
|
||||||
@ -1004,9 +1007,9 @@ class Ticrypto {
|
|||||||
* 生成 uuid
|
* 生成 uuid
|
||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static randomUuid () {
|
static randomize_uuid () {
|
||||||
return uuid.v4()
|
return uuid.v4()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1017,9 +1020,9 @@ class Ticrypto {
|
|||||||
* @param {*} hashList
|
* @param {*} hashList
|
||||||
* @param {*} [option={}]
|
* @param {*} [option={}]
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static getMerkleHash (hashList, { output, hasher } = {}) {
|
static get_merkle_hash ({ hashList, output, hasher } = {}) {
|
||||||
// merkle算法略有难度,暂时用最简单的hash代替
|
// merkle算法略有难度,暂时用最简单的hash代替
|
||||||
if (Array.isArray(hashList)) {
|
if (Array.isArray(hashList)) {
|
||||||
myhasher = crypto.createHash(my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER)
|
myhasher = crypto.createHash(my.HASHER_LIST.includes(hasher) ? hasher : my.HASHER)
|
||||||
@ -1035,14 +1038,14 @@ class Ticrypto {
|
|||||||
* 获取梅克根
|
* 获取梅克根
|
||||||
*
|
*
|
||||||
* @static
|
* @static
|
||||||
* @param {*} todoHashList
|
* @param {*} hashList
|
||||||
* @param {*} option
|
* @param {*} option
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static getMerkleRoot (todoHashList) {
|
static get_merkle_root ({ hashList } = {}) {
|
||||||
//深拷贝传入数组,防止引用对象被改变
|
//深拷贝传入数组,防止引用对象被改变
|
||||||
let hashList = [...todoHashList]
|
hashList = [...hashList]
|
||||||
if (!Array.isArray(hashList)) return null
|
if (!Array.isArray(hashList)) return null
|
||||||
var border = hashList.length
|
var border = hashList.length
|
||||||
if (border == 0) return this.hash('')
|
if (border == 0) return this.hash('')
|
||||||
@ -1075,11 +1078,11 @@ class Ticrypto {
|
|||||||
* @param {*} hash
|
* @param {*} hash
|
||||||
* @param {*} sig
|
* @param {*} sig
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static distanceSig (hash, sig) {
|
static hash_to_sig_distance ({ hash, sig } = {}) {
|
||||||
// hash为64hex字符,sig为128hex字符。返回用hex表达的距离。
|
// 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字节的哈希,同样长度方便比较
|
var hashSig = this.hash(sig) // 把签名也转成32字节的哈希,同样长度方便比较
|
||||||
return new BigInt(hash, 16)
|
return new BigInt(hash, 16)
|
||||||
.subtract(new BigInt(hashSig, 16))
|
.subtract(new BigInt(hashSig, 16))
|
||||||
@ -1097,14 +1100,14 @@ class Ticrypto {
|
|||||||
* @param {*} sig1
|
* @param {*} sig1
|
||||||
* @param {*} sig2
|
* @param {*} sig2
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static compareSig (hash, sig1, sig2) {
|
static compare_signatures ({ hash, sig1, sig2 } = {}) {
|
||||||
// 返回距离hash更近的sig
|
// 返回距离hash更近的sig
|
||||||
if (this.isHash(hash)) {
|
if (this.is_hash({ hash })) {
|
||||||
if (this.isSignature(sig2) && this.isSignature(sig1)) {
|
if (this.is_signature(sig2) && this.is_signature(sig1)) {
|
||||||
var dis1 = this.distanceSig(hash, sig1)
|
var dis1 = this.hash_to_sig_distance({ hash, sig: sig1 })
|
||||||
var dis2 = this.distanceSig(hash, sig2)
|
var dis2 = this.hash_to_sig_distance({ hash, sig: sig2 })
|
||||||
if (dis1 < dis2) {
|
if (dis1 < dis2) {
|
||||||
return sig1
|
return sig1
|
||||||
} else if (dis1 > dis2) {
|
} else if (dis1 > dis2) {
|
||||||
@ -1113,10 +1116,10 @@ class Ticrypto {
|
|||||||
// 如果极其巧合的距离相等,也可能是一个在左、一个在右,那就按 signature 本身的字符串排序来比较。
|
// 如果极其巧合的距离相等,也可能是一个在左、一个在右,那就按 signature 本身的字符串排序来比较。
|
||||||
return sig1 < sig2 ? sig1 : sig1 === sig2 ? sig1 : sig2
|
return sig1 < sig2 ? sig1 : sig1 === sig2 ? sig1 : sig2
|
||||||
}
|
}
|
||||||
} else if (this.isSignature(sig2)) {
|
} else if (this.is_signature(sig2)) {
|
||||||
// 允许其中一个signature是非法的,例如undefined
|
// 允许其中一个signature是非法的,例如undefined
|
||||||
return sig2
|
return sig2
|
||||||
} else if (this.isSignature(sig1)) {
|
} else if (this.is_signature(sig1)) {
|
||||||
return sig1
|
return sig1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1130,13 +1133,13 @@ class Ticrypto {
|
|||||||
* @param {*} hash
|
* @param {*} hash
|
||||||
* @param {*} sigList
|
* @param {*} sigList
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static sortSigList (hash, sigList) {
|
static sort_sig_list ({ hash, sigList } = {}) {
|
||||||
if (Array.isArray(sigList) && this.isHash(hash)) {
|
if (Array.isArray(sigList) && this.is_hash({ hash })) {
|
||||||
sigList.sort(function (sig1, sig2) {
|
sigList.sort(function (sig1, sig2) {
|
||||||
if (this.isSignature(sig1) && this.isSignature(sig2)) {
|
if (this.is_signature(sig1) && this.is_signature(sig2)) {
|
||||||
var winner = this.compareSig(hash, sig1, sig2)
|
var winner = this.compare_signatures({ hash, sig1, sig2 })
|
||||||
if (sig1 === sig2) return 0
|
if (sig1 === sig2) return 0
|
||||||
else if (winner === sig1) return -1
|
else if (winner === sig1) return -1
|
||||||
else if (winner === sig2) return 1
|
else if (winner === sig2) return 1
|
||||||
@ -1189,7 +1192,7 @@ class Ticrypto {
|
|||||||
* @param {*} prikey
|
* @param {*} prikey
|
||||||
* @param {*} signType
|
* @param {*} signType
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static rsaSign (string2Sign, prikey, signType) {
|
static rsaSign (string2Sign, prikey, signType) {
|
||||||
signType = signType || 'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more
|
signType = signType || 'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more
|
||||||
@ -1206,7 +1209,7 @@ class Ticrypto {
|
|||||||
* @param {*} pubkey
|
* @param {*} pubkey
|
||||||
* @param {*} signType
|
* @param {*} signType
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static rsaVerify (string2Verify, signature, pubkey, signType) {
|
static rsaVerify (string2Verify, signature, pubkey, signType) {
|
||||||
signType = signType || 'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more
|
signType = signType || 'RSA-SHA1' // could be RSA-SHA256, RSA-SHA1 or more
|
||||||
@ -1220,7 +1223,7 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} buffer
|
* @param {*} buffer
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static buf_to_hex (buffer) {
|
static buf_to_hex (buffer) {
|
||||||
// buffer is an ArrayBuffer
|
// buffer is an ArrayBuffer
|
||||||
@ -1233,7 +1236,7 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} hex
|
* @param {*} hex
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static hex_to_buf (hex) {
|
static hex_to_buf (hex) {
|
||||||
return new Uint8Array(
|
return new Uint8Array(
|
||||||
@ -1249,7 +1252,7 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} hex
|
* @param {*} hex
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
* 如果出现非HEX的字符,从这个字符(及其同Byte的另一个字符)起直到末尾,都会被忽略掉,但仍然成功返回一个串。
|
* 如果出现非HEX的字符,从这个字符(及其同Byte的另一个字符)起直到末尾,都会被忽略掉,但仍然成功返回一个串。
|
||||||
* bs58check 和 bs58 可接受string, Buffer, ArrayBuffer, Array (包括空字符串'', 各种内容的数组例如包含 undefined,{...},等等);
|
* bs58check 和 bs58 可接受string, Buffer, ArrayBuffer, Array (包括空字符串'', 各种内容的数组例如包含 undefined,{...},等等);
|
||||||
* 不可接受 undefined, null, {...}, 等等,会返回 exception
|
* 不可接受 undefined, null, {...}, 等等,会返回 exception
|
||||||
@ -1276,7 +1279,7 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} box
|
* @param {*} box
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static b58c_to_hex (box) {
|
static b58c_to_hex (box) {
|
||||||
try {
|
try {
|
||||||
@ -1319,7 +1322,7 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} hex
|
* @param {*} hex
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static hex_to_b64t (hex) {
|
static hex_to_b64t (hex) {
|
||||||
if (/^[0-9a-fA-F]+$/.test(hex)) {
|
if (/^[0-9a-fA-F]+$/.test(hex)) {
|
||||||
@ -1334,7 +1337,7 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} b64t
|
* @param {*} b64t
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static b64t_to_hex (b64t) {
|
static b64t_to_hex (b64t) {
|
||||||
if (/^[0-9a-zA-Z\._]+$/.test(b64t)) {
|
if (/^[0-9a-zA-Z\._]+$/.test(b64t)) {
|
||||||
@ -1375,7 +1378,7 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} hex
|
* @param {*} hex
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static hex_to_eip55 (hex) {
|
static hex_to_eip55 (hex) {
|
||||||
if (/^(0x)?[\da-fA-F]+$/.test(hex)) {
|
if (/^(0x)?[\da-fA-F]+$/.test(hex)) {
|
||||||
@ -1402,9 +1405,9 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} uncompressed
|
* @param {*} uncompressed
|
||||||
* @return {*}
|
* @return {*}
|
||||||
* @memberof Ticrypto
|
* @memberof TicCrypto
|
||||||
*/
|
*/
|
||||||
static compressPubkey (uncompressed) {
|
static compress_pubkey (uncompressed) {
|
||||||
// test: https://iancoleman.io/bitcoin-key-compression/
|
// test: https://iancoleman.io/bitcoin-key-compression/
|
||||||
// compress: https://hacpai.com/article/1550844562914
|
// compress: https://hacpai.com/article/1550844562914
|
||||||
// 把 04xy 的非压缩公钥 转成 02x 或 03x 的压缩公钥
|
// 把 04xy 的非压缩公钥 转成 02x 或 03x 的压缩公钥
|
||||||
@ -1415,7 +1418,7 @@ class Ticrypto {
|
|||||||
} else {
|
} else {
|
||||||
compressed = '02' + x // y为偶数=>前缀02
|
compressed = '02' + x // y为偶数=>前缀02
|
||||||
}
|
}
|
||||||
if (this.decompressPubkey(compressed) === uncompressed) {
|
if (this.decompress_pubkey(compressed) === uncompressed) {
|
||||||
return compressed
|
return compressed
|
||||||
}
|
}
|
||||||
return null // 非压缩公钥有错误。
|
return null // 非压缩公钥有错误。
|
||||||
@ -1427,9 +1430,9 @@ class Ticrypto {
|
|||||||
* @static
|
* @static
|
||||||
* @param {*} compressed
|
* @param {*} compressed
|
||||||
* @return {*}
|
* @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
|
// uncompress: https://stackoverflow.com/questions/17171542/algorithm-for-elliptic-curve-point-compression/53478265#53478265
|
||||||
// https://en.bitcoin.it/wiki/Secp256k1
|
// https://en.bitcoin.it/wiki/Secp256k1
|
||||||
// 把 02x 或 03x 的压缩公钥 转成 04xy 的非压缩公钥
|
// 把 02x 或 03x 的压缩公钥 转成 04xy 的非压缩公钥
|
||||||
@ -1512,4 +1515,4 @@ class Ticrypto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 必须单独写 module.exports,不要和类定义写在一起,否则会导致 jsdoc 解析不到类内文档。
|
// 必须单独写 module.exports,不要和类定义写在一起,否则会导致 jsdoc 解析不到类内文档。
|
||||||
module.exports = Ticrypto
|
module.exports = TicCrypto
|
||||||
|
205
test.js
205
test.js
@ -1,59 +1,78 @@
|
|||||||
const bigInt = require("big-integer");
|
const bigInt = require('big-integer')
|
||||||
|
|
||||||
// Consts for secp256k1 curve. Adjust accordingly
|
// Consts for secp256k1 curve. Adjust accordingly
|
||||||
// https://en.bitcoin.it/wiki/Secp256k1
|
// https://en.bitcoin.it/wiki/Secp256k1
|
||||||
const prime = new bigInt('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16), // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
|
const prime = new bigInt('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16), // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
|
||||||
pIdent = new bigInt('3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c', 16) // prime.add(1).divide(4);
|
pIdent = new bigInt('3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c', 16) // prime.add(1).divide(4);
|
||||||
console.log('pIdent=',pIdent.toString(), ' = ', pIdent.toString(16))
|
console.log('pIdent=', pIdent.toString(), ' = ', pIdent.toString(16))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Point decompress secp256k1 curve
|
* Point decompress secp256k1 curve
|
||||||
* @param {string} Compressed representation in hex string
|
* @param {string} Compressed representation in hex string
|
||||||
* @return {string} Uncompressed representation in hex string
|
* @return {string} Uncompressed representation in hex string
|
||||||
*/
|
*/
|
||||||
function ECPointDecompress( comp ) {
|
function ECPointDecompress (comp) {
|
||||||
var signY = new Number(comp[1]) - 2;
|
var signY = new Number(comp[1]) - 2
|
||||||
var x = new bigInt(comp.substring(2), 16);
|
var x = new bigInt(comp.substring(2), 16)
|
||||||
// y mod p = +-(x^3 + 7)^((p+1)/4) mod p
|
// y mod p = +-(x^3 + 7)^((p+1)/4) mod p
|
||||||
console.log('ECP x=', x.toString(), ' = ', x.toString(16))
|
console.log('ECP x=', x.toString(), ' = ', x.toString(16))
|
||||||
var y = x.modPow(3, prime).add(7).mod(prime).modPow( pIdent, prime );
|
var y = x
|
||||||
// If the parity doesn't match it's the *other* root
|
.modPow(3, prime)
|
||||||
console.log('ECP y=', y.toString(), ' = ', y.toString(16))
|
.add(7)
|
||||||
if( y.mod(2).toJSNumber() !== signY ) {
|
.mod(prime)
|
||||||
// y = prime - y
|
.modPow(pIdent, prime)
|
||||||
y = prime.subtract( y );
|
// If the parity doesn't match it's the *other* root
|
||||||
}
|
console.log('ECP y=', y.toString(), ' = ', y.toString(16))
|
||||||
console.log('ECP y=', y.toString(), ' = ', y.toString(16))
|
if (y.mod(2).toJSNumber() !== signY) {
|
||||||
return '04' + x.toString(16).padStart(64, '0') + y.toString(16).padStart(64, '0');
|
// y = prime - y
|
||||||
|
y = prime.subtract(y)
|
||||||
|
}
|
||||||
|
console.log('ECP y=', y.toString(), ' = ', y.toString(16))
|
||||||
|
return '04' + x.toString(16).padStart(64, '0') + y.toString(16).padStart(64, '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
let pubkey1= ECPointDecompress('035d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2')
|
let pubkey1 = ECPointDecompress('035d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2')
|
||||||
console.log(pubkey1) // "045d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b24a323dd24b19c55f0a060ccd4bce314323bd7e804f3dfa8a77f14e3ab1cc4749"
|
console.log(pubkey1) // "045d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b24a323dd24b19c55f0a060ccd4bce314323bd7e804f3dfa8a77f14e3ab1cc4749"
|
||||||
|
|
||||||
correct = "045d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2356d086fb7a78f3ce3359a4caee6dd4fcf0c19a961b1c36b5b442d031d219d75"
|
correct = '045d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2356d086fb7a78f3ce3359a4caee6dd4fcf0c19a961b1c36b5b442d031d219d75'
|
||||||
|
|
||||||
BigNumber = require('bignumber.js')
|
BigNumber = require('bignumber.js')
|
||||||
function uncompressPubkey(comp){
|
function uncompressPubkey (comp) {
|
||||||
// Consts for P256 curve. Adjust accordingly
|
// Consts for P256 curve. Adjust accordingly
|
||||||
const prime = new BigNumber('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16).integerValue(),
|
const prime = new BigNumber('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16).integerValue(),
|
||||||
pIdent = prime.plus(1).idiv(4).integerValue()
|
pIdent = prime
|
||||||
|
.plus(1)
|
||||||
|
.idiv(4)
|
||||||
|
.integerValue()
|
||||||
|
|
||||||
console.log('pIdent=', pIdent.toString(), ' = ', pIdent.toString(16))
|
console.log('pIdent=', pIdent.toString(), ' = ', pIdent.toString(16))
|
||||||
var signY = new Number(comp[1]) - 2;
|
var signY = new Number(comp[1]) - 2
|
||||||
var x = new BigNumber(comp.substring(2), 16).integerValue();
|
var x = new BigNumber(comp.substring(2), 16).integerValue()
|
||||||
console.log('x=',x.toString(), ' = ', x.toString(16))
|
console.log('x=', x.toString(), ' = ', x.toString(16))
|
||||||
// y^2 = x^3 - 3x + b
|
// y^2 = x^3 - 3x + b
|
||||||
var y = x.pow(3).mod(prime).plus(7).mod(prime).pow(pIdent).mod(prime).integerValue();
|
var y = x
|
||||||
console.log('y=',y.toString(), ' = ', y.toString(16))
|
.pow(3)
|
||||||
|
.mod(prime)
|
||||||
|
.plus(7)
|
||||||
|
.mod(prime)
|
||||||
|
.pow(pIdent)
|
||||||
|
.mod(prime)
|
||||||
|
.integerValue()
|
||||||
|
console.log('y=', y.toString(), ' = ', y.toString(16))
|
||||||
// If the parity doesn't match it's the *other* root
|
// If the parity doesn't match it's the *other* root
|
||||||
if( y.mod(2).integerValue().toNumber() !== signY ) {
|
if (
|
||||||
// y = prime - y
|
y
|
||||||
y = prime.minus( y ).integerValue();
|
.mod(2)
|
||||||
|
.integerValue()
|
||||||
|
.toNumber() !== signY
|
||||||
|
) {
|
||||||
|
// y = prime - y
|
||||||
|
y = prime.minus(y).integerValue()
|
||||||
}
|
}
|
||||||
console.log('yy=', y.toString(), ' = ', y.toString(16))
|
console.log('yy=', y.toString(), ' = ', y.toString(16))
|
||||||
return '04' + x.toString(16).padStart(64, '0') + y.toString(16).padStart(64, '0');
|
return '04' + x.toString(16).padStart(64, '0') + y.toString(16).padStart(64, '0')
|
||||||
}
|
}
|
||||||
let pubkey2=uncompressPubkey('035d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2')
|
let pubkey2 = uncompressPubkey('035d77c1e3eac37f685aeea2ae872c4e7e4d159756e57601db3bcccbc549f360b2')
|
||||||
console.log(pubkey2)
|
console.log(pubkey2)
|
||||||
|
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
@ -64,60 +83,61 @@ const keyutil = require('js-crypto-key-utils') // https://github.com/junkurihara
|
|||||||
|
|
||||||
// nodejs cipher/decipher 用同一个密码,在stream上操作。
|
// nodejs cipher/decipher 用同一个密码,在stream上操作。
|
||||||
|
|
||||||
let w = '驳 惊 而 煤 靠 客 示 待 诉 屈 屏 未' // tic.randomSecword('chinese')
|
let w = '驳 惊 而 煤 靠 客 示 待 诉 屈 屏 未' // tic.randomize_secword({lang:'chinese'})
|
||||||
console.log('secword = ', w)
|
console.log('secword = ', w)
|
||||||
|
|
||||||
let acc = tic.secword2account(w, {coin:'ETH'})
|
let acc = tic.secword_to_account({ secword: w, coin: 'ETH' })
|
||||||
console.log('account = ', acc)
|
console.log('account = ', acc)
|
||||||
|
|
||||||
let add = tic.secword2address(w, {coin:'ETH'})
|
let add = tic.secword_to_address({ secword: w, coin: 'ETH' })
|
||||||
console.log('address = ', add)
|
console.log('address = ', add)
|
||||||
|
|
||||||
/////////////////////// keyutil
|
/////////////////////// keyutil
|
||||||
|
|
||||||
let seckeyObject = new keyutil.Key('oct', Buffer.from(acc.seckey, 'hex'), {namedCurve:'P-256K'}) // {P-256 : secp256r1, P-384 : secp384r1, P-521 : secp521r1, P-256K : secp256k1}
|
let seckeyObject = new keyutil.Key('oct', Buffer.from(acc.seckey, 'hex'), { namedCurve: 'P-256K' }) // {P-256 : secp256r1, P-384 : secp384r1, P-521 : secp521r1, P-256K : secp256k1}
|
||||||
let seckeyObject2 = new keyutil.Key('oct', tic.hex_to_buf(acc.seckey, 'hex'), {namedCurve:'P-256K'})
|
let seckeyObject2 = new keyutil.Key('oct', tic.hex_to_buf(acc.seckey, 'hex'), { namedCurve: 'P-256K' })
|
||||||
let seckeyPEM
|
let seckeyPEM
|
||||||
seckeyObject.export('pem').then(data=>seckeyPEM=data)
|
seckeyObject.export('pem').then((data) => (seckeyPEM = data))
|
||||||
let seckeyDER
|
let seckeyDER
|
||||||
seckeyObject2.export('der').then(data=>seckeyDER=data)
|
seckeyObject2.export('der').then((data) => (seckeyDER = data))
|
||||||
|
|
||||||
|
var signerKU = crypto.createSign('sha256')
|
||||||
var signerKU = crypto.createSign('sha256');
|
signerKU.write('毛主席万岁')
|
||||||
signerKU.write('毛主席万岁');
|
signerKU.end()
|
||||||
signerKU.end();
|
var signatureKU = signerKU.sign(seckeyPEM) // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1]
|
||||||
var signatureKU = signerKU.sign(seckeyPEM); // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1]
|
|
||||||
console.log('signature = ', signatureKU.toString('hex'))
|
console.log('signature = ', signatureKU.toString('hex'))
|
||||||
console.log('length = ', signatureKU.toString('hex').length)
|
console.log('length = ', signatureKU.toString('hex').length)
|
||||||
|
|
||||||
var signerKUDER = crypto.createSign('sha256')
|
var signerKUDER = crypto.createSign('sha256')
|
||||||
signerKUDER.write('毛主席万岁');
|
signerKUDER.write('毛主席万岁')
|
||||||
signerKUDER.end();
|
signerKUDER.end()
|
||||||
var signatureKUDER = signerKUDER.sign({key:seckeyDER, format:'der', type:'pkcs8'}); // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1]
|
var signatureKUDER = signerKUDER.sign({ key: seckeyDER, format: 'der', type: 'pkcs8' }) // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1]
|
||||||
console.log('signature DER = ', signatureKUDER.toString('hex'))
|
console.log('signature DER = ', signatureKUDER.toString('hex'))
|
||||||
console.log('length DER = ', signatureKUDER.toString('hex').length)
|
console.log('length DER = ', signatureKUDER.toString('hex').length)
|
||||||
|
|
||||||
|
let pubkeyObject = new keyutil.Key('oct', Buffer.from(acc.pubkey, 'hex'), { namedCurve: 'P-256K' })
|
||||||
let pubkeyObject = new keyutil.Key('oct', Buffer.from(acc.pubkey, 'hex'), {namedCurve:'P-256K'})
|
|
||||||
let pubkeyPEM
|
let pubkeyPEM
|
||||||
pubkeyObject.export('der').then(data=>pubkeyPEM=data)
|
pubkeyObject.export('der').then((data) => (pubkeyPEM = data))
|
||||||
var verifyKU = crypto.createVerify('sha256');
|
var verifyKU = crypto.createVerify('sha256')
|
||||||
verifyKU.write('毛主席万岁');
|
verifyKU.write('毛主席万岁')
|
||||||
verifyKU.end();
|
verifyKU.end()
|
||||||
var verified = verifyKU.verify(pubkeyPEM, signatureKU); // specify format in [pem,der] and type in [pkcs1,spki]
|
var verified = verifyKU.verify(pubkeyPEM, signatureKU) // specify format in [pem,der] and type in [pkcs1,spki]
|
||||||
console.log('verified = ', verified) // 可以验证通过,但是用的privatekey,没有成功使用publickey。
|
console.log('verified = ', verified) // 可以验证通过,但是用的privatekey,没有成功使用publickey。
|
||||||
|
|
||||||
crypto.createCipheriv('aes-256-cfb', Buffer.from(acc.seckey,'hex'), Buffer.alloc(16))
|
crypto.createCipheriv('aes-256-cfb', Buffer.from(acc.seckey, 'hex'), Buffer.alloc(16))
|
||||||
|
|
||||||
////////////////////// crypto + PEM
|
////////////////////// crypto + PEM
|
||||||
|
|
||||||
toPEM=function (kp){
|
toPEM = function (kp) {
|
||||||
let pubkey = crypto.createECDH('secp256k1').setPrivateKey(kp.seckey, 'hex').getPublicKey('hex','compressed')
|
let pubkey = crypto
|
||||||
|
.createECDH('secp256k1')
|
||||||
|
.setPrivateKey(kp.seckey, 'hex')
|
||||||
|
.getPublicKey('hex', 'compressed')
|
||||||
console.log('ECDH created publickey = ', pubkey)
|
console.log('ECDH created publickey = ', pubkey)
|
||||||
let mykey = '308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420' + kp.seckey + 'a144034200' + pubkey
|
let mykey = '308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420' + kp.seckey + 'a144034200' + pubkey
|
||||||
console.log(mykey)
|
console.log(mykey)
|
||||||
let privKey = '-----BEGIN PRIVATE KEY-----\n' + Buffer.from(mykey, 'hex').toString('base64') + '\n-----END PRIVATE KEY-----'
|
let privKey = '-----BEGIN PRIVATE KEY-----\n' + Buffer.from(mykey, 'hex').toString('base64') + '\n-----END PRIVATE KEY-----'
|
||||||
// pubKey2 = crypto.createPublicKey(privKey); //也可恢复出公钥。测试不成功。
|
// pubKey2 = crypto.createPublicKey(privKey); //也可恢复出公钥。测试不成功。
|
||||||
return privKey
|
return privKey
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +148,6 @@ signerPEM.end()
|
|||||||
let signaturePEM = signerPEM.sign(privKeyPEM, 'hex') // 失败,无论对压缩或非压缩公钥
|
let signaturePEM = signerPEM.sign(privKeyPEM, 'hex') // 失败,无论对压缩或非压缩公钥
|
||||||
console.log('signaturePEM = ', signaturePEM)
|
console.log('signaturePEM = ', signaturePEM)
|
||||||
|
|
||||||
|
|
||||||
let pemKP = toPEM(acc)
|
let pemKP = toPEM(acc)
|
||||||
console.log('pemKP = ', pemKP)
|
console.log('pemKP = ', pemKP)
|
||||||
|
|
||||||
@ -136,51 +155,51 @@ console.log('pemKP = ', pemKP)
|
|||||||
// https://stackoverflow.com/questions/58350484/why-nodejs-crypto-sign-function-only-accept-privatekey-pem-format
|
// https://stackoverflow.com/questions/58350484/why-nodejs-crypto-sign-function-only-accept-privatekey-pem-format
|
||||||
// https://www.shangyang.me/2017/05/24/encrypt-rsa-keyformat/
|
// https://www.shangyang.me/2017/05/24/encrypt-rsa-keyformat/
|
||||||
|
|
||||||
var buf1 = Buffer.from('308141020100301306072a8648ce3d020106082a8648ce3d030107042730250201010420', 'hex'); // specific byte-sequence for curve prime256v1
|
var buf1 = Buffer.from('308141020100301306072a8648ce3d020106082a8648ce3d030107042730250201010420', 'hex') // specific byte-sequence for curve prime256v1
|
||||||
var buf2 = Buffer.from(acc.seckey, 'hex'); // raw private key (32 bytes)
|
var buf2 = Buffer.from(acc.seckey, 'hex') // raw private key (32 bytes)
|
||||||
var privateKeyPkcs8Der = Buffer.concat([buf1, buf2], buf1.length + buf2.length);
|
var privateKeyPkcs8Der = Buffer.concat([buf1, buf2], buf1.length + buf2.length)
|
||||||
var sign = crypto.createSign('sha256');
|
var sign = crypto.createSign('sha256')
|
||||||
sign.write('毛主席万岁');
|
sign.write('毛主席万岁')
|
||||||
sign.end();
|
sign.end()
|
||||||
var signature = sign.sign({ key: privateKeyPkcs8Der, format: 'der', type: 'pkcs8' }); // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1]
|
var signature = sign.sign({ key: privateKeyPkcs8Der, format: 'der', type: 'pkcs8' }) // specify format in [pem,der] and type in [pkcs1, pkcs8, sec1]
|
||||||
console.log('signature = ', signature.toString('hex'))
|
console.log('signature = ', signature.toString('hex'))
|
||||||
console.log('length = ', signature.toString('hex').length)
|
console.log('length = ', signature.toString('hex').length)
|
||||||
|
|
||||||
var buf3 = Buffer.from('3059301306072a8648ce3d020106082a8648ce3d030107034200', 'hex'); // specific byte-sequence for curve prime256v1
|
var buf3 = Buffer.from('3059301306072a8648ce3d020106082a8648ce3d030107034200', 'hex') // specific byte-sequence for curve prime256v1
|
||||||
var buf4 = Buffer.from(acc.pubkey, 'hex'); // raw public key (uncompressed, 65 bytes, startting with 04)
|
var buf4 = Buffer.from(acc.pubkey, 'hex') // raw public key (uncompressed, 65 bytes, startting with 04)
|
||||||
// 这个key无法sign。reason: 'too long'
|
// 这个key无法sign。reason: 'too long'
|
||||||
//var publicKeyX509Der = Buffer.concat([buf3, buf4], buf3.length + buf4.length);
|
//var publicKeyX509Der = Buffer.concat([buf3, buf4], buf3.length + buf4.length);
|
||||||
//var publicKey = crypto.createPublicKey({key:publicKeyX509Der, format:'der', type:'spki'})
|
//var publicKey = crypto.createPublicKey({key:publicKeyX509Der, format:'der', type:'spki'})
|
||||||
var publicKey = crypto.createPublicKey({ key: privateKeyPkcs8Der, type: 'pkcs8', format: 'der' });
|
var publicKey = crypto.createPublicKey({ key: privateKeyPkcs8Der, type: 'pkcs8', format: 'der' })
|
||||||
var publicKeyX509Der = publicKey.export({type: 'spki', format: 'der'})
|
var publicKeyX509Der = publicKey.export({ type: 'spki', format: 'der' })
|
||||||
var verify = crypto.createVerify('sha256');
|
var verify = crypto.createVerify('sha256')
|
||||||
verify.write('毛主席万岁');
|
verify.write('毛主席万岁')
|
||||||
verify.end();
|
verify.end()
|
||||||
var verified = verify.verify({ key: publicKeyX509Der, format: 'der', type: 'spki' }, signature); // specify format in [pem,der] and type in [pkcs1,spki]
|
var verified = verify.verify({ key: publicKeyX509Der, format: 'der', type: 'spki' }, signature) // specify format in [pem,der] and type in [pkcs1,spki]
|
||||||
console.log('verified = ', verified) // 可以验证通过,但是用的privatekey,没有成功使用publickey。
|
console.log('verified = ', verified) // 可以验证通过,但是用的privatekey,没有成功使用publickey。
|
||||||
|
|
||||||
/////////////////////// elliptic
|
/////////////////////// elliptic
|
||||||
|
|
||||||
var EC = require('elliptic').ec;
|
var EC = require('elliptic').ec
|
||||||
// Create and initialize EC context
|
// Create and initialize EC context
|
||||||
// (better do it once and reuse it)
|
// (better do it once and reuse it)
|
||||||
var ec = new EC('secp256k1');
|
var ec = new EC('secp256k1')
|
||||||
// Generate keys
|
// Generate keys
|
||||||
//var key = ec.genKeyPair();
|
//var key = ec.genKeyPair();
|
||||||
var key = ec.keyFromPrivate(acc.seckey) // 注意,不需要 'hex' 参数
|
var key = ec.keyFromPrivate(acc.seckey) // 注意,不需要 'hex' 参数
|
||||||
// Sign the message's hash (input must be an array, or a hex-string)
|
// Sign the message's hash (input must be an array, or a hex-string)
|
||||||
var msgHash = tic.hash('毛主席万岁')
|
var msgHash = tic.hash('毛主席万岁')
|
||||||
var msgHashBad = tic.hash('毛主席万岁 ')
|
var msgHashBad = tic.hash('毛主席万岁 ')
|
||||||
var signature2 = key.sign(msgHash);
|
var signature2 = key.sign(msgHash)
|
||||||
// Export DER encoded signature in Array
|
// Export DER encoded signature in Array
|
||||||
var derSign = signature2.toDER(); // 无法直接导出成 hex。可以
|
var derSign = signature2.toDER() // 无法直接导出成 hex。可以
|
||||||
console.log('signature by elliptic = ', Buffer.from(derSign).toString('hex'))
|
console.log('signature by elliptic = ', Buffer.from(derSign).toString('hex'))
|
||||||
// 或者重新创建使用 pubkey,也能成功
|
// 或者重新创建使用 pubkey,也能成功
|
||||||
// ec.keyFromPublic(acc.pubkey, 'hex').verify(msgHash, signature2)
|
// ec.keyFromPublic(acc.pubkey, 'hex').verify(msgHash, signature2)
|
||||||
console.log(key.verify(msgHash, signature2))
|
console.log(key.verify(msgHash, signature2))
|
||||||
console.log(key.verify(msgHashBad, signature2))
|
console.log(key.verify(msgHashBad, signature2))
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
/*
|
/*
|
||||||
createCipher/Decipher: 使用 pwd, 对称加解密。已放弃。
|
createCipher/Decipher: 使用 pwd, 对称加解密。已放弃。
|
||||||
createCipheriv/Deciperiv: 使用 key, 对称加解密。
|
createCipheriv/Deciperiv: 使用 key, 对称加解密。
|
||||||
|
Loading…
Reference in New Issue
Block a user