u
This commit is contained in:
parent
71eb5d5dce
commit
d54cc58c80
@ -213,7 +213,7 @@
|
||||
<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"/>
|
||||
</mxCell>
|
||||
<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">
|
||||
<mxCell id="111" value="prikey_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"/>
|
||||
</mxCell>
|
||||
<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">
|
||||
@ -222,7 +222,7 @@
|
||||
<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"/>
|
||||
</mxCell>
|
||||
<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">
|
||||
<mxCell id="114" value="prikey_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"/>
|
||||
</mxCell>
|
||||
<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">
|
||||
|
70
ticc.js
70
ticc.js
@ -31,6 +31,7 @@ my.INPUT = 'utf8' // 默认的加密方法的明文格式。utf8 能够兼容 la
|
||||
my.INPUT_LIST = ['utf8', 'ascii', 'latin1'] // ignored for Buffer/TypedArray/DataView
|
||||
my.COIN = 'TIC' // 默认的币种
|
||||
my.COIN_LIST = ['TIC', 'BTC', 'ETH']
|
||||
my.WORLD = 'COMET'
|
||||
my.REGEXP_ALPHABET = {
|
||||
hex: /^[0-9a-fA-F]+$/,
|
||||
b32: /^[A-Za-z2-7=]+$/,
|
||||
@ -142,7 +143,7 @@ class TicCrypto {
|
||||
* @return {Boolean}
|
||||
* @memberof TicCrypto
|
||||
*/
|
||||
static is_seckey ({ prikey } = {}) {
|
||||
static is_prikey ({ prikey } = {}) {
|
||||
// 比特币、以太坊的私钥:64 hex
|
||||
// nacl.sign 的私钥 128 hex, nacl.box 的私钥 64 hex
|
||||
return /^([a-fA-F0-9]{128}|[a-fA-F0-9]{64})$/.test(prikey)
|
||||
@ -230,8 +231,8 @@ class TicCrypto {
|
||||
}
|
||||
} else if (keytype === 'prikey') {
|
||||
// 尚未走通,不能使用 ticc 生成的 Elliptic curve 椭圆曲线算法公私钥,只能用 crypto.generateKeyPairSync('rsa') 生成的 rsa 公私钥
|
||||
let seckeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
|
||||
return crypto.privateEncrypt(seckeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
|
||||
let prikeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
|
||||
return crypto.privateEncrypt(prikeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
|
||||
} else if (keytype === 'pubkey') {
|
||||
let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem')
|
||||
return crypto.publicEncrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。
|
||||
@ -274,8 +275,8 @@ class TicCrypto {
|
||||
}
|
||||
} else if (keytype === 'prikey') {
|
||||
// 尚未走通,不能使用 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。每次结果都一样。
|
||||
let prikeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
|
||||
return crypto.privateDecrypt(prikeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果都一样。
|
||||
} else if (keytype === 'pubkey') {
|
||||
let pubkeyPEM = await new keyman.Key('oct', this.hex_to_buf(key), { namedCurve: 'P-256K' }).export('pem')
|
||||
return crypto.publicDecrypt(pubkeyPEM, Buffer.from(data)) // 返回 Buffer。每次结果不一样。
|
||||
@ -295,24 +296,24 @@ class TicCrypto {
|
||||
*/
|
||||
static async sign_easy ({ data, prikey, tool = 'crypto', hasher = my.HASHER }) {
|
||||
// data can be string or buffer or object, results are the same
|
||||
if (this.is_hashable({ data }) && this.is_seckey({ prikey })) {
|
||||
if (this.is_hashable({ data }) && this.is_prikey({ prikey })) {
|
||||
if (tool === 'nacl' && prikey.length === 128) {
|
||||
// 使用nacl的签名算法。注意,nacl.sign需要的seckey是64字节=128字符。
|
||||
// 使用 nacl 的签名算法。注意,nacl.sign 需要的 prikey 是64字节=128字符。
|
||||
let hashBuf = this.hash_easy(data, { output: 'buf' }) // 哈希必须输出为 buffer
|
||||
let signature = nacl.sign.detached(hashBuf, Buffer.from(prikey, 'hex'))
|
||||
return Buffer.from(signature).toString('hex') // 签名是64节,128个hex字符
|
||||
} else if (tool === 'eccrypto' && prikey.length === 64) {
|
||||
// eccrypto 对同一组data,seckey生成的签名是固定的,观察到hex长度为140或142,是der格式。
|
||||
// eccrypto 对同一组data, prikey 生成的签名是固定的,观察到hex长度为140或142,是der格式。
|
||||
let signature = await eccrypto.sign(Buffer.from(prikey, 'hex'), this.hash_easy(data, { output: 'buf' }))
|
||||
return signature.toString('hex')
|
||||
} else if (prikey.length === 64) {
|
||||
// 纯 crypto
|
||||
let seckeyPEM = await new keyman.Key('oct', this.hex_to_buf(prikey), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
|
||||
let prikeyPEM = await new keyman.Key('oct', this.hex_to_buf(prikey), { namedCurve: 'P-256K' }).export('pem') // 私钥导出的der格式为144字节。
|
||||
let signer = crypto.createSign(hasher) // 注意,不知为何,hasher必须含有'sha'才能完成签名,例如 sha1, sha256, sha512, sha3, RSA-SHA1, id-rsassa-pkcs1-v1_5-with-sha3-224, 其他都会报错。
|
||||
signer.update(this.hash_easy(data)).end()
|
||||
let signature = signer.sign(seckeyPEM, 'hex')
|
||||
let signature = signer.sign(prikeyPEM, 'hex')
|
||||
// since nodejs 12, 有了 crypto.sign 方法,但在浏览器中无效:
|
||||
// let signature = crypto.sign(hasher, Buffer.from(this.hash_easy(data)), seckeyPEM).toString('hex')
|
||||
// let signature = crypto.sign(hasher, Buffer.from(this.hash_easy(data)), prikeyPEM).toString('hex')
|
||||
return signature // 发现同样的输入,nodejs里每次调用会生成不同的 signature, 且长度不定(140,142,144 hex) 但都可以通过 verify。但在浏览器里调用,signature却是固定的。
|
||||
}
|
||||
}
|
||||
@ -441,7 +442,7 @@ class TicCrypto {
|
||||
// 但可以不断延伸下去:/xxx/xxx/xxx/xxx/...
|
||||
coin = coin?.toUpperCase?.() || my.COIN
|
||||
|
||||
if (!this.is_secword(secword)) {
|
||||
if (!this.is_secword({ secword })) {
|
||||
// 由于 secword_to_seed 可以对一切字符串都正常返回,为防止secword为空,在这里先做检查。
|
||||
return null
|
||||
}
|
||||
@ -550,15 +551,20 @@ class TicCrypto {
|
||||
* @return {Object}
|
||||
* @memberof TicCrypto
|
||||
*/
|
||||
static secword_to_account ({ secword, coin = my.COIN, world, pass, pathRoot, pathIndex, path, tool, hasher } = {}) {
|
||||
static secword_to_account ({ secword, coin, world, pass, pathRoot, pathIndex, path, tool, hasher } = {}) {
|
||||
// account 比 keypair 多了 address 字段。
|
||||
coin = coin?.toUpperCase?.() || my.COIN
|
||||
let kp = this.secword_to_keypair({ secword, coin, pass, pathRoot, pathIndex, path, tool, hasher })
|
||||
if (kp) {
|
||||
if (coin === 'ETH') {
|
||||
world = world || 'mainnet'
|
||||
let uncompressedPubkey = this.decompress_pubkey(kp.pubkey)
|
||||
kp.address = this.pubkey_to_address({ pubkey: uncompressedPubkey, coin: 'ETH', world })
|
||||
} else if (coin === 'BTC') {
|
||||
world = world || 'mainnet'
|
||||
kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin, world })
|
||||
} else {
|
||||
world = world || my.WORLD
|
||||
kp.address = this.pubkey_to_address({ pubkey: kp.pubkey, coin, world })
|
||||
}
|
||||
return Object.assign(kp, { coin, world, secword })
|
||||
@ -575,19 +581,9 @@ class TicCrypto {
|
||||
* @return {String} address
|
||||
* @memberof TicCrypto
|
||||
*/
|
||||
static secword_to_address ({ secword, coin = my.COIN, world, pass, pathRoot, pathIndex, path, tool, hasher } = {}) {
|
||||
coin = coin?.toUpperCase?.() || my.COIN
|
||||
let kp = this.secword_to_keypair({ secword, coin, pass, pathRoot, pathIndex, path, tool, hasher })
|
||||
if (kp) {
|
||||
let address
|
||||
if (coin === 'ETH') {
|
||||
address = this.pubkey_to_address({ pubkey: this.decompress_pubkey(kp.pubkey), coin: 'ETH', world })
|
||||
} else {
|
||||
address = this.pubkey_to_address({ pubkey: kp.pubkey, coin, world })
|
||||
}
|
||||
return address
|
||||
}
|
||||
return null
|
||||
static secword_to_address ({ secword, coin, world, pass, pathRoot, pathIndex, path, tool, hasher } = {}) {
|
||||
const account = this.secword_to_account({ secword, coin, world, pass, pathRoot, pathIndex, path, tool, hasher })
|
||||
return account?.address
|
||||
}
|
||||
|
||||
/**
|
||||
@ -599,8 +595,8 @@ class TicCrypto {
|
||||
* @return {*}
|
||||
* @memberof TicCrypto
|
||||
*/
|
||||
static seckey_to_pubkey ({ prikey, curve, compress } = {}) {
|
||||
if (this.is_seckey({ prikey }) && prikey.length === 64) {
|
||||
static prikey_to_pubkey ({ prikey, curve, compress } = {}) {
|
||||
if (this.is_prikey({ prikey }) && prikey.length === 64) {
|
||||
// 只能用于32字节的私钥(BTC, ETH)。也就是不能用于 TIC 的私钥。
|
||||
curve = my.CURVE_LIST.includes(curve) ? curve : my.CURVE // 默认为 secp256k1
|
||||
// return new crypto.createECDH(curve).setPrivateKey(prikey,'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')
|
||||
@ -614,7 +610,7 @@ class TicCrypto {
|
||||
// return ecc.getPublicCompressed(this.hex_to_buf(prikey)).toString('hex')
|
||||
// }
|
||||
// 注意,Buffer.from(nacl.box.keyPair.fromSecretKey(Buffer.from(prikey,'hex')).publicKey).toString('hex') 得到的公钥与上面的不同
|
||||
} else if (this.is_seckey({ prikey }) && prikey.length === 128) {
|
||||
} else if (this.is_prikey({ prikey }) && prikey.length === 128) {
|
||||
// 用于64字节=128 hex的 TIC 私钥
|
||||
let keypair = nacl.sign.keyPair.fromSecretKey(Buffer.from(prikey, 'hex'))
|
||||
return Buffer.from(keypair.publicKey).toString('hex') // 测试过 不能直接keypair.publicKey.toString('hex'),不是buffer类型
|
||||
@ -631,16 +627,16 @@ class TicCrypto {
|
||||
* @return {*}
|
||||
* @memberof TicCrypto
|
||||
*/
|
||||
static seckey_to_address ({ prikey, coin, world } = {}) {
|
||||
static prikey_to_address ({ prikey, coin, world } = {}) {
|
||||
coin = coin?.toUpperCase() || my.COIN
|
||||
if (this.is_seckey({ prikey })) {
|
||||
if (this.is_prikey({ prikey })) {
|
||||
/** @type {*} */
|
||||
let pubkey
|
||||
if (coin === 'ETH') {
|
||||
pubkey = this.seckey_to_pubkey({ prikey, compress: false })
|
||||
pubkey = this.prikey_to_pubkey({ prikey, compress: false })
|
||||
return this.pubkey_to_address({ pubkey: pubkey, coin, world })
|
||||
} else {
|
||||
pubkey = this.seckey_to_pubkey({ prikey, compress: true })
|
||||
pubkey = this.prikey_to_pubkey({ prikey, compress: true })
|
||||
return this.pubkey_to_address({ pubkey: pubkey, coin, world })
|
||||
}
|
||||
}
|
||||
@ -696,7 +692,7 @@ class TicCrypto {
|
||||
*/
|
||||
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
|
||||
coin = coin?.toUpperCase?.() || my.COIN
|
||||
let address
|
||||
if (coin === 'ETH') {
|
||||
// 对以太坊,按照 EIP55,把纯位置转换为大小写敏感能自我验证的hex地址。仍然为20节=40符。
|
||||
@ -757,7 +753,7 @@ class TicCrypto {
|
||||
prefix = '74'
|
||||
break // Base58: 0x90 => d, Base 64: d=0x1d=0b00011101 => 0b 011101xx = 0x74~77
|
||||
default:
|
||||
prefix = '4c'
|
||||
prefix = '74'
|
||||
}
|
||||
let checksum = this.hash_easy(this.hash_easy(prefix + position)).slice(0, 6) // 添加 checksum 使得能够检测大小写错误。[todo] 校验码里要不要包含 prefix?
|
||||
// address = this.hex_to_eip55(prefix + position + checksum) // 前缀1节,位置20节,校验3节,共24节=48字符(能够完全转化为8个色彩),再转eip55。
|
||||
@ -837,7 +833,7 @@ class TicCrypto {
|
||||
*/
|
||||
static pubkey_to_address ({ pubkey, coin, world } = {}) {
|
||||
// pubkey 应当是string类型
|
||||
coin = coin?.toUpperCase() || my.COIN
|
||||
coin = coin?.toUpperCase?.() || my.COIN
|
||||
return this.position_to_address({ position: this.pubkey_to_position({ pubkey, coin }), coin, world })
|
||||
}
|
||||
|
||||
@ -920,7 +916,7 @@ class TicCrypto {
|
||||
}
|
||||
} else {
|
||||
let prikey = this.randomize_seckey()
|
||||
let pubkey = this.seckey_to_pubkey({ prikey })
|
||||
let pubkey = this.prikey_to_pubkey({ prikey })
|
||||
return {
|
||||
prikey,
|
||||
pubkey,
|
||||
|
Loading…
Reference in New Issue
Block a user