|
|
|
|
@ -1,72 +1,107 @@
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
// 引入大整数库bn.js,用于处理大整数运算
|
|
|
|
|
var BN = require('bn.js');
|
|
|
|
|
// 用于实现JavaScript中的继承机制
|
|
|
|
|
var inherits = require('inherits');
|
|
|
|
|
// 引入Base类,可能是一个基础的抽象类或者包含了一些通用的功能,具体要看其定义
|
|
|
|
|
var Base = require('./base');
|
|
|
|
|
|
|
|
|
|
// 引入一些工具函数,具体功能要看其内部实现
|
|
|
|
|
var utils = require('../utils');
|
|
|
|
|
|
|
|
|
|
// MontCurve类,代表蒙哥马利曲线,继承自Base类
|
|
|
|
|
function MontCurve(conf) {
|
|
|
|
|
Base.call(this, 'mont', conf);
|
|
|
|
|
// 调用Base类的构造函数,传入曲线类型'mont'和配置信息conf
|
|
|
|
|
Base.call(this,'mont', conf);
|
|
|
|
|
|
|
|
|
|
// 将十六进制表示的配置参数conf.a转换为大整数,并转换到蒙哥马利域(通过toRed方法,this.red应该是蒙哥马利域相关的设置)
|
|
|
|
|
this.a = new BN(conf.a, 16).toRed(this.red);
|
|
|
|
|
// 同理,处理配置参数conf.b
|
|
|
|
|
this.b = new BN(conf.b, 16).toRed(this.red);
|
|
|
|
|
// 将整数4转换为大整数并转换到蒙哥马利域,然后求其乘法逆元(在蒙哥马利域内)
|
|
|
|
|
this.i4 = new BN(4).toRed(this.red).redInvm();
|
|
|
|
|
// 将整数2转换为大整数并转换到蒙哥马利域
|
|
|
|
|
this.two = new BN(2).toRed(this.red);
|
|
|
|
|
// 计算a24,具体计算公式看代码逻辑,涉及到前面计算的一些值
|
|
|
|
|
this.a24 = this.i4.redMul(this.a.redAdd(this.two));
|
|
|
|
|
}
|
|
|
|
|
// 实现MontCurve类继承自Base类的继承关系
|
|
|
|
|
inherits(MontCurve, Base);
|
|
|
|
|
// 将MontCurve类作为模块对外暴露,方便其他模块使用
|
|
|
|
|
module.exports = MontCurve;
|
|
|
|
|
|
|
|
|
|
// MontCurve类的实例方法,用于验证一个点是否在蒙哥马利曲线上
|
|
|
|
|
MontCurve.prototype.validate = function validate(point) {
|
|
|
|
|
// 获取点的横坐标x,并进行归一化处理(具体看normalize方法的实现)
|
|
|
|
|
var x = point.normalize().x;
|
|
|
|
|
// 计算横坐标x的平方(在蒙哥马利域内)
|
|
|
|
|
var x2 = x.redSqr();
|
|
|
|
|
// 按照蒙哥马利曲线的方程右边部分进行计算(涉及乘法、加法等运算,都是在蒙哥马利域内)
|
|
|
|
|
var rhs = x2.redMul(x).redAdd(x2.redMul(this.a)).redAdd(x);
|
|
|
|
|
// 计算rhs的平方根(在蒙哥马利域内)
|
|
|
|
|
var y = rhs.redSqrt();
|
|
|
|
|
|
|
|
|
|
// 比较y的平方和rhs是否相等,以此判断点是否在曲线上,返回比较结果(0表示相等)
|
|
|
|
|
return y.redSqr().cmp(rhs) === 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类,代表曲线上的点,继承自Base.BasePoint类(具体要看Base.BasePoint的定义)
|
|
|
|
|
function Point(curve, x, z) {
|
|
|
|
|
// 调用Base.BasePoint类的构造函数,传入曲线类型和'projective'标识,具体作用看其定义
|
|
|
|
|
Base.BasePoint.call(this, curve, 'projective');
|
|
|
|
|
if (x === null && z === null) {
|
|
|
|
|
// 如果传入的横坐标x和竖坐标z都为null,将横坐标设为曲线的单位元(通常表示无穷远点相关概念)
|
|
|
|
|
this.x = this.curve.one;
|
|
|
|
|
// 将竖坐标设为曲线的零元素
|
|
|
|
|
this.z = this.curve.zero;
|
|
|
|
|
} else {
|
|
|
|
|
// 将传入的十六进制表示的横坐标x转换为大整数
|
|
|
|
|
this.x = new BN(x, 16);
|
|
|
|
|
// 将传入的十六进制表示的竖坐标z转换为大整数
|
|
|
|
|
this.z = new BN(z, 16);
|
|
|
|
|
if (!this.x.red)
|
|
|
|
|
// 如果横坐标的大整数还未转换到蒙哥马利域,进行转换(通过曲线的相关设置this.curve.red)
|
|
|
|
|
this.x = this.x.toRed(this.curve.red);
|
|
|
|
|
if (!this.z.red)
|
|
|
|
|
// 同理,对竖坐标进行转换到蒙哥马利域的操作
|
|
|
|
|
this.z = this.z.toRed(this.curve.red);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 实现Point类继承自Base.BasePoint类的继承关系
|
|
|
|
|
inherits(Point, Base.BasePoint);
|
|
|
|
|
|
|
|
|
|
// MontCurve类的实例方法,用于从字节数据解码出曲线上的一个点(根据给定的编码格式enc)
|
|
|
|
|
MontCurve.prototype.decodePoint = function decodePoint(bytes, enc) {
|
|
|
|
|
return this.point(utils.toArray(bytes, enc), 1);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// MontCurve类的实例方法,用于创建一个曲线上的点对象,传入横坐标x和竖坐标z(或默认值)
|
|
|
|
|
MontCurve.prototype.point = function point(x, z) {
|
|
|
|
|
return new Point(this, x, z);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// MontCurve类的实例方法,用于从JSON数据创建一个曲线上的点对象(具体要看JSON数据的格式要求等)
|
|
|
|
|
MontCurve.prototype.pointFromJSON = function pointFromJSON(obj) {
|
|
|
|
|
return Point.fromJSON(this, obj);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,预计算相关(目前这里是无操作,可能后续会添加具体逻辑)
|
|
|
|
|
Point.prototype.precompute = function precompute() {
|
|
|
|
|
// No-op
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,用于将点编码为字节数组(大端序,长度根据曲线的某个属性curve.p.byteLength()确定)
|
|
|
|
|
Point.prototype._encode = function _encode() {
|
|
|
|
|
return this.getX().toArray('be', this.curve.p.byteLength());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的静态方法,用于从JSON数据创建一个Point对象,传入曲线对象和JSON数据
|
|
|
|
|
Point.fromJSON = function fromJSON(curve, obj) {
|
|
|
|
|
return new Point(curve, obj[0], obj[1] || curve.one);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,用于返回点的字符串表示形式,方便调试等查看
|
|
|
|
|
Point.prototype.inspect = function inspect() {
|
|
|
|
|
if (this.isInfinity())
|
|
|
|
|
return '<EC Point Infinity>';
|
|
|
|
|
@ -74,105 +109,115 @@ Point.prototype.inspect = function inspect() {
|
|
|
|
|
' z: ' + this.z.fromRed().toString(16, 2) + '>';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,用于判断点是否为无穷远点(通过比较竖坐标是否为0来判断,这里假设在蒙哥马利域内零的表示是固定的)
|
|
|
|
|
Point.prototype.isInfinity = function isInfinity() {
|
|
|
|
|
// XXX This code assumes that zero is always zero in red
|
|
|
|
|
return this.z.cmpn(0) === 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,用于实现点的加倍操作(按照蒙哥马利曲线的相关算法实现,参考了特定的文档链接)
|
|
|
|
|
Point.prototype.dbl = function dbl() {
|
|
|
|
|
// http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#doubling-dbl-1987-m-3
|
|
|
|
|
// 2M + 2S + 4A
|
|
|
|
|
// 2M + 2S + 4A,表示此操作涉及到的乘法、平方和加法的次数(大概是性能评估相关的注释)
|
|
|
|
|
|
|
|
|
|
// A = X1 + Z1
|
|
|
|
|
// A = X1 + Z1,计算横坐标和竖坐标的和(在蒙哥马利域内)
|
|
|
|
|
var a = this.x.redAdd(this.z);
|
|
|
|
|
// AA = A^2
|
|
|
|
|
// AA = A^2,计算a的平方(在蒙哥马利域内)
|
|
|
|
|
var aa = a.redSqr();
|
|
|
|
|
// B = X1 - Z1
|
|
|
|
|
// B = X1 - Z1,计算横坐标和竖坐标的差(在蒙哥马利域内)
|
|
|
|
|
var b = this.x.redSub(this.z);
|
|
|
|
|
// BB = B^2
|
|
|
|
|
// BB = B^2,计算b的平方(在蒙哥马利域内)
|
|
|
|
|
var bb = b.redSqr();
|
|
|
|
|
// C = AA - BB
|
|
|
|
|
// C = AA - BB,计算aa和bb的差(在蒙哥马利域内)
|
|
|
|
|
var c = aa.redSub(bb);
|
|
|
|
|
// X3 = AA * BB
|
|
|
|
|
// X3 = AA * BB,计算新的横坐标(在蒙哥马利域内)
|
|
|
|
|
var nx = aa.redMul(bb);
|
|
|
|
|
// Z3 = C * (BB + A24 * C)
|
|
|
|
|
// Z3 = C * (BB + A24 * C),计算新的竖坐标(在蒙哥马利域内)
|
|
|
|
|
var nz = c.redMul(bb.redAdd(this.curve.a24.redMul(c)));
|
|
|
|
|
return this.curve.point(nx, nz);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,加法操作,这里直接抛出不支持的错误(说明蒙哥马利曲线可能不支持这种简单的加法形式)
|
|
|
|
|
Point.prototype.add = function add() {
|
|
|
|
|
throw new Error('Not supported on Montgomery curve');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,差分加法操作(按照蒙哥马利曲线的相关算法实现,参考了特定的文档链接)
|
|
|
|
|
Point.prototype.diffAdd = function diffAdd(p, diff) {
|
|
|
|
|
// http://hyperelliptic.org/EFD/g1p/auto-montgom-xz.html#diffadd-dadd-1987-m-3
|
|
|
|
|
// 4M + 2S + 6A
|
|
|
|
|
// 4M + 2S + 6A,表示此操作涉及到的乘法、平方和加法的次数(大概是性能评估相关的注释)
|
|
|
|
|
|
|
|
|
|
// A = X2 + Z2
|
|
|
|
|
// A = X2 + Z2,计算当前点的横坐标和竖坐标的和(在蒙哥马利域内)
|
|
|
|
|
var a = this.x.redAdd(this.z);
|
|
|
|
|
// B = X2 - Z2
|
|
|
|
|
// B = X2 - Z2,计算当前点的横坐标和竖坐标的差(在蒙哥马利域内)
|
|
|
|
|
var b = this.x.redSub(this.z);
|
|
|
|
|
// C = X3 + Z3
|
|
|
|
|
// C = X3 + Z3,计算传入点p的横坐标和竖坐标的和(在蒙哥马利域内)
|
|
|
|
|
var c = p.x.redAdd(p.z);
|
|
|
|
|
// D = X3 - Z3
|
|
|
|
|
// D = X3 - Z3,计算传入点p的横坐标和竖坐标的差(在蒙哥马利域内)
|
|
|
|
|
var d = p.x.redSub(p.z);
|
|
|
|
|
// DA = D * A
|
|
|
|
|
// DA = D * A,计算d和a的乘积(在蒙哥马利域内)
|
|
|
|
|
var da = d.redMul(a);
|
|
|
|
|
// CB = C * B
|
|
|
|
|
// CB = C * B,计算c和b的乘积(在蒙哥马利域内)
|
|
|
|
|
var cb = c.redMul(b);
|
|
|
|
|
// X5 = Z1 * (DA + CB)^2
|
|
|
|
|
// X5 = Z1 * (DA + CB)^2,计算新的横坐标(在蒙哥马利域内)
|
|
|
|
|
var nx = diff.z.redMul(da.redAdd(cb).redSqr());
|
|
|
|
|
// Z5 = X1 * (DA - CB)^2
|
|
|
|
|
// Z5 = X1 * (DA - CB)^2,计算新的竖坐标(在蒙哥马利域内)
|
|
|
|
|
var nz = diff.x.redMul(da.redISub(cb).redSqr());
|
|
|
|
|
return this.curve.point(nx, nz);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,点乘操作,实现了一种基于二进制分解的点乘算法(具体逻辑看代码内循环等操作)
|
|
|
|
|
Point.prototype.mul = function mul(k) {
|
|
|
|
|
var t = k.clone();
|
|
|
|
|
var a = this; // (N / 2) * Q + Q
|
|
|
|
|
var b = this.curve.point(null, null); // (N / 2) * Q
|
|
|
|
|
var c = this; // Q
|
|
|
|
|
var a = this; // (N / 2) * Q + Q,表示当前点相关的一种中间状态
|
|
|
|
|
var b = this.curve.point(null, null); // (N / 2) * Q,表示另一种中间状态
|
|
|
|
|
var c = this; // Q,表示初始的点
|
|
|
|
|
|
|
|
|
|
for (var bits = []; t.cmpn(0) !== 0; t.iushrn(1))
|
|
|
|
|
for (var bits = []; t.cmpn(0)!== 0; t.iushrn(1))
|
|
|
|
|
bits.push(t.andln(1));
|
|
|
|
|
|
|
|
|
|
for (var i = bits.length - 1; i >= 0; i--) {
|
|
|
|
|
if (bits[i] === 0) {
|
|
|
|
|
// N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q
|
|
|
|
|
// N * Q + Q = ((N / 2) * Q + Q)) + (N / 2) * Q,根据二进制位进行相应的点运算更新
|
|
|
|
|
a = a.diffAdd(b, c);
|
|
|
|
|
// N * Q = 2 * ((N / 2) * Q + Q))
|
|
|
|
|
// N * Q = 2 * ((N / 2) * Q + Q)),更新中间状态
|
|
|
|
|
b = b.dbl();
|
|
|
|
|
} else {
|
|
|
|
|
// N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q)
|
|
|
|
|
// N * Q = ((N / 2) * Q + Q) + ((N / 2) * Q),根据二进制位进行相应的点运算更新
|
|
|
|
|
b = a.diffAdd(b, c);
|
|
|
|
|
// N * Q + Q = 2 * ((N / 2) * Q + Q)
|
|
|
|
|
// N * Q + Q = 2 * ((N / 2) * Q + Q),更新中间状态
|
|
|
|
|
a = a.dbl();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return b;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,乘法加法操作,这里直接抛出不支持的错误(说明蒙哥马利曲线可能不支持这种操作形式)
|
|
|
|
|
Point.prototype.mulAdd = function mulAdd() {
|
|
|
|
|
throw new Error('Not supported on Montgomery curve');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,jumlAdd操作(具体不清楚是什么操作,这里直接抛出不支持的错误)
|
|
|
|
|
Point.prototype.jumlAdd = function jumlAdd() {
|
|
|
|
|
throw new Error('Not supported on Montgomery curve');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,用于比较两个点是否相等(通过比较横坐标是否相等来判断)
|
|
|
|
|
Point.prototype.eq = function eq(other) {
|
|
|
|
|
return this.getX().cmp(other.getX()) === 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,用于对坐标进行归一化处理(将横坐标乘以竖坐标的逆元,竖坐标设为曲线的单位元)
|
|
|
|
|
Point.prototype.normalize = function normalize() {
|
|
|
|
|
this.x = this.x.redMul(this.z.redInvm());
|
|
|
|
|
this.z = this.curve.one;
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Point类的实例方法,用于获取归一化后的横坐标(先进行归一化处理,再从蒙哥马利域转换出来)
|
|
|
|
|
Point.prototype.getX = function getX() {
|
|
|
|
|
// Normalize coordinates
|
|
|
|
|
this.normalize();
|
|
|
|
|
|
|
|
|
|
return this.x.fromRed();
|
|
|
|
|
};
|
|
|
|
|
};
|