Skip to content
This repository was archived by the owner on Nov 13, 2021. It is now read-only.
ox0spy edited this page Apr 22, 2019 · 2 revisions

基础知识

所有加密,签名,运算所需要的函数,都在 /utility.js 文件中可以找到参考实现。

单向散列函数

单向散列函数,是一种将长消息转换为短散列值的技术,用于确保消息完整性。

Keccak 是一种符合 SHA-3 标准的单向散列函数,可以生成任意长度的散列值。PRS 项目使用的是 Keccak-256 SHA3 算法,在 JavaScript 中使用的开源库是 js-sha3

示例:

const jsSha3 = require('js-sha3');

let keccak256 = (message) => {
    return jsSha3.keccak256(message);
};

椭圆曲线密码

椭圆曲线密码是一种利用椭圆曲线数学来实现的密码技术的统称,是一种建立公钥密码的算法。

Secp256k1 是比特币使用的 ECDSA (椭圆曲线数字签名算法)曲线的参数,并且在高效密码学标准 (Certicom Research) 中进行了定义. PRS 项目也使用该算法来进行数字签名,在 JavaScript 中使用的开源库是 elliptic

更多内容可参考: 公开密钥加密 椭圆曲线密码学

数字签名

数字签名是一种将类似现实世界中物理签名、盖章,在计算机世界中进行实现的技术。是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。使用数字签名可以识别篡改和伪造,还可以防止否认,具有不可抵赖性。

签名以及验证过程过程:

  1. A 用单向散列函数求出消息的散列值。
  2. A 用自己的私钥对散列值进行加密(即签名)。
  3. A 将消息和签名发送给 B。
  4. B 用 A 的公钥对收到的签名进行解密。
  5. B 将解密后得到的散列值,与 A 直接发送的消息的散列值进行对比验证。

以下是进行签名的过程,具体实现参考/utility.js

const sign = (message, privatekey) => {
    // 1. 用单向散列函数 keccak256 求出消息的散列值
    const msghash = keccak256(message);
    return signByMsghash(msghash, privatekey);
}

const signByMsghash = (msghash, privatekey) => {
    // 2.  用自己的私钥对散列值进行加密
    const existingPrivKey =  ec.keyFromPrivate(privatekey , 'hex');
    const signature       = existingPrivKey.sign(msghash);
    const combinedHex     = signature.r.toString(16, 32)
                          + signature.s.toString(16, 32)
                          + signature.recoveryParam.toString();
    return {sig: combinedHex, msghash: msghash};
};

创建秘钥对

在数字签名中,签名的生成和验证使用不同的秘钥。生成签名使用的秘钥被称为私钥,验证签名使用的秘钥被称为公钥,任何人都能够使用公钥验证签名。

创建秘钥对过程:

  1. 用随机数生成秘钥,因为秘钥需要具有不易被他人推测的性质。
  2. 通过椭圆曲线签名算法,推导出公钥。
  3. 从公钥经过 Keccak 单向散列函数推导出地址。
let createKeyPair = (options = {}) => {
    // 1. 用随机数生成秘钥,因为秘钥需要具有不易被他人推测的性质。
    let privateKey = createPrivateKey();
    // 2. 通过椭圆曲线签名算法,推导出公钥。
    let publishKey = createPublicKeyByPrivateKey(privateKey);
    let convertKey = secp256k1.publicKeyConvert(publishKey, false).slice(1);
    // 3. 从公钥经过 Keccak 单向散列函数推导出地址。
    let publishAdd = ethUtil.pubToAddress(convertKey);
    return {
        privateKey : fetchKey(privateKey, options),
        publishKey : fetchKey(publishKey, options),
        address    : fetchKey(publishAdd, options),
    };
};

let createPrivateKey = (options = {}) => {
    let privateKey;
    do {
      privateKey = crypto.randomBytes(32)
    } while (!secp256k1.privateKeyVerify(privateKey))
    return fetchKey(privateKey, options);
};

let createPublicKeyByPrivateKey = (privateKey, options = {}) => {
    return fetchKey(secp256k1.publicKeyCreate(privateKey), options);
};

在 PRESS.one 中,推导出的地址就是区分用户的唯一 ID。

Keystore

Keystore文件是以太坊钱包存储私钥的一种文件格式(JSON),它使用用户自定义密码加密,以起到一定程度上的保护作用,而保护的程度取决于用户加密该钱包的密码强度。

PRESS.one 使用的 keystore 格式是 eth 标准格式, 在 JavaScript 中使用的是开源库是 keythereum

具体格式如:

{"address":"c2d7cf95645d33006175b78989035c7c9061d3f9",
  "crypto":{
    "cipher":"aes-128-ctr",
    "ciphertext":"0f6d343b2a34fe571639235fc16250823c6fe3bc30525d98c41dfdf21a97aedb",
    "cipherparams":{
      "iv":"cabce7fb34e4881870a2419b93f6c796"
    },
    "kdf":"scrypt",
    "kdfparams":{
      "dklen":32,
      "n":262144,
      "p":1,
      "r":8,
      "salt":"1af9c4a44cf45fe6fb03dcc126fa56cb0f9e81463683dd6493fb4dc76edddd51"
    },
    "mac":"5cf4012fffd1fbe41b122386122350c3825a709619224961a16e908c2a366aa6"
  },
  "id":"eddd71dd-7ad6-4cd3-bc1a-11022f7db76c",
  "version":3
}

获取私钥

通过 Keystore 文件加上密码,即可解密出用户的私钥,拿到私钥即可进行数字签名。

const keythereum = require('keythereum');

const privatekey = keythereum.recover(password, keystore);

Clone this wiki locally