-
Notifications
You must be signed in to change notification settings - Fork 12
Base
所有加密,签名,运算所需要的函数,都在 /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。
数字签名是一种将类似现实世界中物理签名、盖章,在计算机世界中进行实现的技术。是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。使用数字签名可以识别篡改和伪造,还可以防止否认,具有不可抵赖性。
签名以及验证过程过程:
- A 用单向散列函数求出消息的散列值。
- A 用自己的私钥对散列值进行加密(即签名)。
- A 将消息和签名发送给 B。
- B 用 A 的公钥对收到的签名进行解密。
- 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};
};在数字签名中,签名的生成和验证使用不同的秘钥。生成签名使用的秘钥被称为私钥,验证签名使用的秘钥被称为公钥,任何人都能够使用公钥验证签名。
创建秘钥对过程:
- 用随机数生成秘钥,因为秘钥需要具有不易被他人推测的性质。
- 通过椭圆曲线签名算法,推导出公钥。
- 从公钥经过 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文件是以太坊钱包存储私钥的一种文件格式(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);