Skip to content

Commit

Permalink
improvement(ddn-crypto): change js-nacl to tweetnacl.js etc
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Improved encryption algorithm, unified encryption management and improved
comprehensive performance
  • Loading branch information
imfly committed Jan 29, 2020
1 parent 2c60168 commit a3ad7ad
Show file tree
Hide file tree
Showing 17 changed files with 305 additions and 184 deletions.
63 changes: 62 additions & 1 deletion doc/ddn-cli.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,64 @@
# DDN 命令行工具

从 DDN v3.0.0 以后,我们的命令行工具`ddn-cli`名称正式更改为`ddn`,也就是说,通过命令行操作的命令与实际运行的程序将保持一次,都是`ddn`.
从 DDN v3.0.0 以后,我们的命令行工具`ddn-cli`名称正式更改为`ddn`,也就是说,通过命令行操作的命令与实际运行的程序将保持一次,都是`ddn`.

```
imflydeMacBook:ddn imfly$ ddn
Usage: [options] [command]
Options:
-V, --version output the version number
-H, --host <host> Specify the hostname or ip of the node, default: 127.0.0.1 (default: "127.0.0.1")
-P, --port <port> Specify the port of the node, default: 8001 (default: 8001)
-M, --main Specify the mainnet, default: false
-h, --help output usage information
Commands:
getHeight get block height
getBlockstatus get block status
openAccount [secret] open your account and get the infomation by secret
openAccountByPublickey [publickey] open your account and get the infomation by publickey
getBalance [address] get balance by address
getAccount [address] get account by address
getVotedDelegates [options] [address] get delegates voted by address
getDelegatesCount get delegates count
getDelegates [options] get delegates
getVoters [publicKey] get voters of a delegate by public key
getDelegateByPublickey [publicKey] get delegate by public key
getDelegateByUsername [username] get delegate by username
getBlocks [options] get blocks
getBlockById [id] get block by id
getBlockByHeight [height] get block by height
getPeers [options] get peers
getUnconfirmedTransactions [options] get unconfirmed transactions
getTransactions [options] get transactions
getTransaction [id] get transactions
sendToken [options] send token to some address
sendAsset [options] send asset to some address
registerDelegate [options] register delegate
listDiffVotes [options] list the votes each other
upVote [options] vote for delegates
downVote [options] cancel vote for delegates
setSecondsecret [options] set second secret
registerDapp [options] register a dapp
deposit [options] deposit assets to an app
dappTransaction [options] create a dapp transaction
lock [options] lock account transfer
getFullBlockById [id] get full block by block id
getFullBlockByHeight [height] get full block by block height
getTransactionBytes [options] get transaction bytes
getTransactionId [options] get transaction id
getBlockBytes [options] get block bytes
getBlockPayloadHash [options] get block bytes
getBlockId [options] get block id
verifyBytes [options] verify bytes/signature/publickey
generate|g <asset> <name> generate new blockchain
contract [options] contract operations
crypto [options] crypto operations
dapps [options] manage your dapps
createGenesis [options] create genesis block
peerStat analyze block height of all peers
delegateStat analyze delegates status
ipStat analyze peer ip info
createUsers [options] create some accounts
```
47 changes: 35 additions & 12 deletions doc/ddn-crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,50 @@ Base58加密原理:和通常base64编码一样,base58编码的作用也是

参考:[bs58.js](../packages/ddn-crypto/src/base58check/bs58.js)

## 生成地址
## 生成地址(公钥)

1. 获取一个随机的32字节ECDSA密钥

2. 使用椭圆曲线加密算法计算上述私钥所对应的非压缩公钥
私钥:
2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09

3. 对(压缩)公钥进行SHA-256哈希计算
ECDSA,就是椭圆曲线数字签名算法,是使用椭圆曲线密码(ECC)对数字签名算法(DSA)的模拟,即:ECC与DSA的结合,整个签名过程与DSA类似,所不一样的是签名中采取的算法为ECC,最后签名出来的值也是分为r,s。ECDSA于1999年成为ANSI标准,并于2000年成为IEEE和NIST标准。

4. 对步骤2的哈希值进行RIPEMD-160哈希计算
签名过程如下:
1、选择一条椭圆曲线Ep(a,b),和基点G;
2、选择私有密钥k(k<n,n为G的阶),利用基点G计算公开密钥K=kG;
3、产生一个随机整数r(r<n),计算点R=rG;
4、将原数据和点R的坐标值x,y作为参数,计算SHA1做为hash,即Hash=SHA1(原数据,x,y);
5、计算s≡r - Hash * k (mod n)
6、r和s做为签名值,如果r和s其中一个为0,重新从第3步开始执行

5. 在步骤3的哈希值前添加前缀(主网为0x00,测试网为0xef)
验证过程如下:
1、接受方在收到消息(m)和签名值(r,s)后,进行以下运算
2、计算:sG+H(m)P=(x1,y1), r1≡ x1 mod p。
3、验证等式:r1 ≡ r mod p。
4、如果等式成立,接受签名,否则签名无效。

6. 对步骤4的扩展RIPEMD-160哈希值进行SHA256哈希计算
私钥本质上是一个随机数,由32个byte组成的数组,1个byte等于8位二进制,一个二进制只有两个值0或者1。所以私钥的总数是将近2^(8*32)=2^256个,但是有一些私钥并不能使用,他真实的大小是介于:1 ~ 0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4141之间的数。这个数量已经超过了宇宙中原子的总数,想要遍历所有的私钥,耗尽整个太阳的能量也是不可能的。

7. 对步骤5的哈希值再次进行SHA256哈希计算
1. 使用椭圆曲线加密算法计算上述私钥所对应的非压缩公钥

8. 取步骤6结果值的前4个字节作为校验码

9. 将校验码添加到步骤4的扩展RIPEMD-160哈希值末尾
公钥:
5d036a858ce89f844491762eb89e2bfbd50a4a0a0da658e4b2628b25b117ae09

10. 使用Base58Check编码将结果从字节字符串转换为base58字符串。
2. 对(压缩)公钥进行SHA-256哈希计算

3. 对步骤2的哈希值进行RIPEMD-160哈希计算

4. 使用Base58Check编码将结果从字节字符串转换为base58字符串。

5. 在步骤3的哈希值前添加前缀(比如:D)

与比特币比较,我们并没有添加`校验码``版本号`的过程,而是简化为独立标识的`D`等。

5. 对步骤4的扩展RIPEMD-160哈希值进行HA256哈希计算
6. 对步骤5的哈希值再次进行SHA256哈希计算
7. 取步骤6结果值的前4个字节作为
8. 将校验码添加到步骤4的扩展RIPEMD-160哈希值末尾

## 验证地址

Expand All @@ -36,4 +59,4 @@ Base58加密原理:和通常base64编码一样,base58编码的作用也是
3. 把字节数组(2)两次Sha256 Hash
4. 取字节数组(2)hash后的前4位,跟字节数组(1)比较。如果相同校验通过。
5. 校验通过的解码字节数组取第一个字节,地址前缀。
6. 检验前缀的合法性(根据主网参数校验),注意大小写。
6. 检验前缀的合法性(根据主网参数校验),注意大小写。
101 changes: 57 additions & 44 deletions packages/ddn-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,58 +8,71 @@ A command line tool to manage [DDN](https://github.com/ddnlink) blockchain apps.
最新的dapps系列子命令要求node版本号为v8.4.0以上

```
npm install -g @ddn/ddn
npm install -g @ddn/ddn-cli
```

## Usage

```
$ ddn --help
$ ddn
Usage: ddn [options] [command]
Usage: [options] [command]
Commands:
Options:
-V, --version output the version number
-H, --host <host> Specify the hostname or ip of the node, default: 127.0.0.1 (default: "127.0.0.1")
-P, --port <port> Specify the port of the node, default: 8001 (default: 8001)
-M, --main Specify the mainnet, default: false
-h, --help output usage information
getheight get block height
getblockstatus get block status
openaccount [secret] open your account and get the infomation by secret
openaccountbypublickey [publickey] open your account and get the infomation by publickey
getbalance [address] get balance by address
getaccount [address] get account by address
getvoteddelegates [options] [address] get delegates voted by address
getdelegatescount get delegates count
getdelegates [options] get delegates
getvoters [publicKey] get voters of a delegate by public key
getdelegatebypublickey [publicKey] get delegate by public key
getdelegatebyusername [username] get delegate by username
getblocks [options] get blocks
getblockbyid [id] get block by id
getblockbyheight [height] get block by height
getpeers [options] get peers
getunconfirmedtransactions [options] get unconfirmed transactions
gettransactions [options] get transactions
gettransaction [id] get transactions
sendmoney [options] send money to some address
registerdelegate [options] register delegate
upvote [options] vote for delegates
downvote [options] cancel vote for delegates
setsecondsecret [options] set second secret
registerdapp [options] register a dapp
contract [options] contract operations
crypto [options] crypto operations
dapps [options] manage your dapps
creategenesis [options] create genesis block
peerstat analyze block height of all peers
delegatestat analyze delegates status
ipstat analyze peer ip info
Options:
-h, --help output usage information
-V, --version output the version number
-H, --host <host> Specify the hostname or ip of the node, default: 127.0.0.1
-P, --port <port> Specify the port of the node, default: 8001
-M, --main Specify the mainnet, default: false
Commands:
getHeight get block height
getBlockstatus get block status
openAccount [secret] open your account and get the infomation by secret
openAccountByPublickey [publickey] open your account and get the infomation by publickey
getBalance [address] get balance by address
getAccount [address] get account by address
getVotedDelegates [options] [address] get delegates voted by address
getDelegatesCount get delegates count
getDelegates [options] get delegates
getVoters [publicKey] get voters of a delegate by public key
getDelegateByPublickey [publicKey] get delegate by public key
getDelegateByUsername [username] get delegate by username
getBlocks [options] get blocks
getBlockById [id] get block by id
getBlockByHeight [height] get block by height
getPeers [options] get peers
getUnconfirmedTransactions [options] get unconfirmed transactions
getTransactions [options] get transactions
getTransaction [id] get transactions
sendToken [options] send token to some address
sendAsset [options] send asset to some address
registerDelegate [options] register delegate
listDiffVotes [options] list the votes each other
upVote [options] vote for delegates
downVote [options] cancel vote for delegates
setSecondsecret [options] set second secret
registerDapp [options] register a dapp
deposit [options] deposit assets to an app
dappTransaction [options] create a dapp transaction
lock [options] lock account transfer
getFullBlockById [id] get full block by block id
getFullBlockByHeight [height] get full block by block height
getTransactionBytes [options] get transaction bytes
getTransactionId [options] get transaction id
getBlockBytes [options] get block bytes
getBlockPayloadHash [options] get block bytes
getBlockId [options] get block id
verifyBytes [options] verify bytes/signature/publickey
generate|g <asset> <name> generate new blockchain
contract [options] contract operations
crypto [options] crypto operations
dapps [options] manage your dapps
createGenesis [options] create genesis block
peerStat analyze block height of all peers
delegateStat analyze delegates status
ipStat analyze peer ip info
createUsers [options] create some accounts
```

## Documents
Expand Down
6 changes: 3 additions & 3 deletions packages/ddn-cli/src/helpers/account.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
var crypto = require('@ddn/ddn-crypto');
const crypto = require('@ddn/ddn-crypto');

module.exports = {
account: function (secret, tokenPrefix) {
if (!tokenPrefix) {
tokenPrefix = 'D';
}

var kp = crypto.keypair(secret);
var address = crypto.getAddress(Buffer.from(kp.publicKey, 'hex'), tokenPrefix);
const kp = crypto.keypair(secret);
const address = crypto.generateAddress(Buffer.from(kp.publicKey, 'hex'), tokenPrefix);

return {
keypair: kp,
Expand Down
4 changes: 2 additions & 2 deletions packages/ddn-crypto/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
},
"dependencies": {
"bitcore-mnemonic": "^8.5.1",
"js-nacl": "0.6.0",
"fast-sha256": "^1.3.0"
"fast-sha256": "^1.3.0",
"tweetnacl": "^1.0.2"
}
}
48 changes: 27 additions & 21 deletions packages/ddn-crypto/src/crypto.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
/*---------------------------------------------------------------------------------------------
* Created by Imfly on Wed Jan 29 2020 11:48:54
*
* Copyright (c) 2019 DDN FOUNDATION. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import sha256 from "fast-sha256";
import RIPEMD160 from "ripemd160";
import nacl_factory from "js-nacl";
import crypto from "crypto";
import Mnemonic from "bitcore-mnemonic";
import base58check from "./base58check";
import nacl from 'tweetnacl';

const nacl = nacl_factory.instantiate();

function getHash(data) {
return crypto
.createHash("sha256")
.update(data, "utf8")
.digest();
}
function randomName() {
// Convert arguments to Array
const array = Array.prototype.slice.apply(arguments);
Expand Down Expand Up @@ -48,29 +46,29 @@ function randomString(max) {

function keypair(secret) {
const hash = getHash(secret);
const kp = nacl.crypto_sign_keypair_from_seed(hash);

const keypair = {
publicKey: Buffer.from(kp.signPk).toString("hex"),
privateKey: Buffer.from(kp.signSk).toString("hex")
};
const keypair = nacl.sign.keyPair.fromSeed(hash);

return keypair;
return {
publicKey: bufToHex(keypair.publicKey),
privateKey: bufToHex(keypair.secretKey)
}
}

// TODO: sign(keypair, data) -> sign(data, keypair)
function sign(keypair, data) {
const hash = getHash(data);
const signature = nacl.crypto_sign_detached(
const signature = nacl.sign.detached(
hash,
Buffer.from(keypair.privateKey, "hex")
);
return Buffer.from(signature).toString("hex");
return bufToHex(signature);
}

function getId(data) {
return getHash(data).toString("hex");
}

// 生成助记词 == ddn-node-sdk.crypto.generatePhasekey()
function generateSecret() {
return new Mnemonic(Mnemonic.Words.ENGLISH).toString();
}
Expand Down Expand Up @@ -102,7 +100,7 @@ function isAddress(address, tokenPrefix) {
return true;
}

function getAddress(publicKey, tokenPrefix) {
function generateAddress(publicKey, tokenPrefix) {
if (typeof publicKey === "string") {
publicKey = Buffer.from(publicKey, "hex");
}
Expand All @@ -111,6 +109,14 @@ function getAddress(publicKey, tokenPrefix) {
return tokenPrefix + base58check.encode(h2);
}

function getHash(data) {
return Buffer.from(sha256.hash(Buffer.from(data)));
}

function bufToHex(data) {
return Buffer.from(data).toString("hex");
}

export default {
keypair,
sign,
Expand All @@ -119,7 +125,7 @@ export default {
randomNethash,
generateSecret,
isValidSecret,
getAddress,
generateAddress,
base58check,
isAddress
};
4 changes: 3 additions & 1 deletion packages/ddn-crypto/src/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
module.exports = require('./crypto');
import crypto from './crypto';

export default crypto;
Loading

0 comments on commit a3ad7ad

Please sign in to comment.