Ed25519签名算法介绍
Ed25519作者
Daniel J. Bernstein 是世界著名的密码学家
优势
完全开放设计,算法各个参数直接了当,明确,很大的概率通过缓存、时间、恶意输入摧毁安全性,而 25519 系列椭圆曲线经过特别设计,尽可能的将出错的概率降到了最低,25519 系列曲线是目前最快的椭圆曲线加密算法,一个4核2.4GHz 的 Westmere cpu,每秒可以验证 71000 个签名,吊打同类:椭圆曲线是 NIST
基本特点
公共钥只有32字节,私钥只有64字节
实战node,js生成Ed25519密钥对
目标
通过tweetnacl生成原始的Uint8Array密钥对,生成公钥,私钥类型首字母G,S写入Buffer,然后私钥写入Buffer,通过上面Buffer计算校验码再次写入buffer,最后使用base32编码。生成用户常规保存的字符串。
首先安装依赖包
npm I tweetnacl crc lodash base32.js —save
解释简单解释说明下包的作用
tweetnacl: 最核心的包,是用javascript接口实现的TweetNaci/Naci端口,它实现了密钥加密解密,公钥验证加密,公共签名,hash等。我们将使用这个库生成,原始的Uint8Array密钥对。也可以自己随机一个64byte私钥,然后解析为keypair。
crc:生成校验码的
lodash:是一个一致性、模块化、高性能的 JavaScript 实用工具库。
base32.js:由于原生方法,只有base64,所以引入base32.js进行编码解码
具体代码实现
//各种引入
const nacl = require(“tweetnacl");
const crc = require("crc");
const base32 = require("base32.js")
const isUndefined = require("lodash/isUndefined");
const isNull = require("lodash/isNull");
const isString = require("lodash/isString");
const versionBytes = {
ed25519PublicKey: 6 << 3, // G
ed25519SecretSeed: 18 << 3, // S
preAuthTx: 19 << 3, // T
sha256Hash: 23 << 3 // X
};
//封装一个类,构造函数中生成keypair,提供静态编码解码公钥私钥方法
class Keypair {
constructor(){
this.orikeypair = nacl.sign.keyPair();
this.publicKey = Buffer.from(this.orikeypair.publicKey);
console.log(this.orikeypair.publicKey);
this.privateKey = Buffer.from(this.orikeypair.secretKey);
}
static encodeCheck(versionByteName, data) {
if (isNull(data) || isUndefined(data)) {
throw new Error("cannot encode null data");
}
let versionByte = versionBytes[versionByteName];
if (isUndefined(versionByte)) {
throw new Error(`${versionByteName} is not a valid version byte name. expected one of "ed25519PublicKey", "ed25519SecretSeed", "preAuthTx", "sha256Hash"`);
}
data = Buffer.from(data);
let versionBuffer = Buffer.from([versionByte]);
let payload = Buffer.concat([versionBuffer, data]);
let checksum = calculateChecksum(payload);
let unencoded = Buffer.concat([payload, checksum]);
return base32.encode(unencoded);
}
static decodeCheck(versionByteName, encoded) {
if (!isString(encoded)) {
throw new TypeError('encoded argument must be of type String');
}
let decoded = base32.decode(encoded);
let versionByte = decoded[0];
let payload = decoded.slice(0, -2);
let data = payload.slice(1);
let checksum = decoded.slice(-2);
if (encoded != base32.encode(decoded)) {
throw new Error('invalid encoded string');
}
let expectedVersion = versionBytes[versionByteName];
if (isUndefined(expectedVersion)) {
throw new Error(`${versionByteName} is not a valid version byte name. expected one of "accountId" or "seed"`);
}
if (versionByte !== expectedVersion) {
throw new Error(`invalid version byte. expected ${expectedVersion}, got ${versionByte}`);
}
let expectedChecksum = calculateChecksum(payload);
if (!verifyChecksum(expectedChecksum, checksum)) {
throw new Error(`invalid checksum`);
}
return Buffer.from(data);
}
}
function calculateChecksum(payload) {
// This code calculates CRC16-XModem checksum of payload
// and returns it as Buffer in little-endian order.
let checksum = Buffer.alloc(2);
checksum.writeUInt16LE(crc.crc16xmodem(payload), 0);
return checksum;
}
//测试使用
let newKeypair = new Keypair();
console.log(newKeypair.publicKey);
let newPublic = Keypair.encodeCheck("ed25519PublicKey",newKeypair.publicKey);
let newPrivate = Keypair.encodeCheck("ed25519SecretSeed",newKeypair.privateKey);
let publicBuffer = Keypair.decodeCheck("ed25519PublicKey",newPublic);
console.log(newPublic,newPrivate);
console.log(publicBuffer);
说明
相关包的详细api可以直接复制包名字在github查找
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。