11 #12

Merged
pamj3bxuk merged 2 commits from branc_yz into main 1 year ago

@ -449,48 +449,96 @@ Point.prototype.normalize = function normalize() {
this.zOne = true; // 设置标志为 true
return this; // 返回归一化后的点
};
Point.prototype.neg = function neg() {
return this.curve.point(this.x.redNeg(),
this.y,
this.z,
this.t && this.t.redNeg());
// 在投影坐标系中执行点的加法
Point.prototype._projAdd = function _projAdd(p) {
// 参考文献: hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
// #addition-add-2008-bbjlp
// #addition-add-2007-bl
// 计算复杂度: 10M + 1S
// A = Z1 * Z2
var a = this.z.redMul(p.z); // 计算 A两个点的 z 坐标的乘积
// B = A^2
var b = a.redSqr(); // 计算 BA 的平方
// C = X1 * X2
var c = this.x.redMul(p.x); // 计算 C两个点的 x 坐标的乘积
// D = Y1 * Y2
var d = this.y.redMul(p.y); // 计算 D两个点的 y 坐标的乘积
// E = d * C * D
var e = this.curve.d.redMul(c).redMul(d); // 计算 E涉及曲线参数 d
// F = B - E
var f = b.redSub(e); // 计算 F
// G = B + E
var g = b.redAdd(e); // 计算 G
// X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D)
var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d; // 计算 tmp
var nx = a.redMul(f).redMul(tmp); // 计算新点的 x 坐标
var ny; // 新点的 y 坐标
var nz; // 新点的 z 坐标
if (this.curve.twisted) { // 如果曲线是扭曲的
// Y3 = A * G * (D - a * C)
ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c))); // 计算新点的 y 坐标
// Z3 = F * G
nz = f.redMul(g); // 计算新点的 z 坐标
} else { // 如果曲线不是扭曲的
// Y3 = A * G * (D - C)
ny = a.redMul(g).redMul(d.redSub(c)); // 计算新点的 y 坐标
// Z3 = c * F * G
nz = this.curve._mulC(f).redMul(g); // 计算新点的 z 坐标
}
return this.curve.point(nx, ny, nz); // 返回新计算的点
};
Point.prototype.getX = function getX() {
this.normalize();
return this.x.fromRed();
// 点的加法方法
Point.prototype.add = function add(p) {
if (this.isInfinity()) // 如果当前点是无穷大,返回 p
return p;
if (p.isInfinity()) // 如果 p 是无穷大,返回当前点
return this;
// 根据曲线的坐标系统调用相应的加法方法
if (this.curve.extended)
return this._extAdd(p); // 调用扩展坐标加法方法
else
return this._projAdd(p); // 调用投影坐标加法方法
};
Point.prototype.getY = function getY() {
this.normalize();
return this.y.fromRed();
// 点的倍乘方法
Point.prototype.mul = function mul(k) {
// 如果 k 有重复的倍增操作,使用固定的 NAF 乘法
if (this._hasDoubles(k))
return this.curve._fixedNafMul(this, k);
else // 否则使用 WNAF 乘法
return this.curve._wnafMul(this, k);
};
Point.prototype.eq = function eq(other) {
return this === other ||
this.getX().cmp(other.getX()) === 0 &&
this.getY().cmp(other.getY()) === 0;
// 进行加法的倍乘方法
Point.prototype.mulAdd = function mulAdd(k1, p, k2) {
// 使用 WNAF 乘法加法,返回结果
return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, false);
};
Point.prototype.eqXToP = function eqXToP(x) {
var rx = x.toRed(this.curve.red).redMul(this.z);
if (this.x.cmp(rx) === 0)
return true;
var xc = x.clone();
var t = this.curve.redN.redMul(this.z);
for (;;) {
xc.iadd(this.curve.n);
if (xc.cmp(this.curve.p) >= 0)
return false;
rx.redIAdd(t);
if (this.x.cmp(rx) === 0)
return true;
}
// 在 Jacobian 坐标系下进行加法的倍乘方法
Point.prototype.jmulAdd = function jmulAdd(k1, p, k2) {
// 使用 WNAF 乘法加法,返回结果
return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2, true);
};
// Compatibility with BaseCurve
Point.prototype.toP = Point.prototype.normalize;
Point.prototype.mixedAdd = Point.prototype.add;
// 归一化点的坐标
Point.prototype.normalize = function normalize() {
if (this.zOne) // 如果 z 坐标为 1直接返回当前点
return this;
// 计算 z 的逆
var zi = this.z.redInvm();
this.x = this.x.redMul(zi); // 归一化 x 坐标
this.y = this.y.redMul(zi); // 归一化 y 坐标
if (this.t) // 如果有 t 坐标
this.t = this.t.redMul(zi); // 归一化 t 坐标
this.z = this.curve.one; // 将 z 坐标设为 1
this.zOne = true; // 设置标志为 true
return this; // 返回归一化后的点
};

@ -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();
};
};

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save