From 22717739ac008b962a2802784cf997225636e121 Mon Sep 17 00:00:00 2001 From: yangzhen <3104844212@qq.com> Date: Tue, 17 Dec 2024 14:38:56 +0800 Subject: [PATCH 1/2] 11 --- .../elliptic/lib/elliptic/curve/edwards.js | 118 +++++++++---- .../elliptic/lib/elliptic/curve/mont.js | 99 ++++++++--- .../elliptic/lib/elliptic/curve/short.js | 160 ++++++++++++++---- 3 files changed, 284 insertions(+), 93 deletions(-) diff --git a/node_modules/elliptic/lib/elliptic/curve/edwards.js b/node_modules/elliptic/lib/elliptic/curve/edwards.js index 8e2ede5..5984044 100644 --- a/node_modules/elliptic/lib/elliptic/curve/edwards.js +++ b/node_modules/elliptic/lib/elliptic/curve/edwards.js @@ -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(); // 计算 B,A 的平方 + // 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; // 返回归一化后的点 +}; diff --git a/node_modules/elliptic/lib/elliptic/curve/mont.js b/node_modules/elliptic/lib/elliptic/curve/mont.js index 4b9f80f..7c96e48 100644 --- a/node_modules/elliptic/lib/elliptic/curve/mont.js +++ b/node_modules/elliptic/lib/elliptic/curve/mont.js @@ -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 ''; @@ -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(); -}; +}; \ No newline at end of file diff --git a/node_modules/elliptic/lib/elliptic/curve/short.js b/node_modules/elliptic/lib/elliptic/curve/short.js index eec36ec..ae58df6 100644 --- a/node_modules/elliptic/lib/elliptic/curve/short.js +++ b/node_modules/elliptic/lib/elliptic/curve/short.js @@ -1,62 +1,87 @@ 'use strict'; +// 引入工具函数模块,具体功能要看其内部实现,可能包含一些常用的辅助函数等 var utils = require('../utils'); +// 引入大整数库bn.js,用于处理大整数相关的运算 var BN = require('bn.js'); +// 用于实现JavaScript中的继承机制 var inherits = require('inherits'); +// 引入Base类,可能是一个基础的抽象类或者包含了一些通用的功能,具体要看其定义 var Base = require('./base'); +// 获取utils模块中的assert函数,通常用于进行条件断言,若条件不满足则抛出异常 var assert = utils.assert; +// ShortCurve类,代表一种特定的曲线(可能是短曲线之类的概念,具体要看业务场景),继承自Base类 function ShortCurve(conf) { - Base.call(this, 'short', conf); + // 调用Base类的构造函数,传入曲线类型'short'和配置信息conf + Base.call(this,'short', 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); + // 计算2在蒙哥马利域内的乘法逆元,赋值给tinv,可能后续用于相关运算 this.tinv = this.two.redInvm(); + // 判断曲线的参数a转换为普通整数后是否为0,将结果保存在zeroA属性中,用于后续判断曲线的一些特性 this.zeroA = this.a.fromRed().cmpn(0) === 0; - this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0; + // 判断曲线的参数a转换为普通整数后减去某个值(这里应该是this.p所代表的值)是否等于 -3,将结果保存在threeA属性中,同样用于后续判断 + this.threeA = this.a.fromRel().sub(this.p).cmpn(-3) === 0; - // If the curve is endomorphic, precalculate beta and lambda + // 判断曲线是否具有自同态性质,并预先计算相关的自同态参数(beta和lambda等),将结果保存在endo属性中 this.endo = this._getEndomorphism(conf); + // 初始化两个数组,可能用于存储与自同态相关的中间数据或者计算结果,具体要看后续使用情况 this._endoWnafT1 = new Array(4); this._endoWnafT2 = new Array(4); } +// 实现ShortCurve类继承自Base类的继承关系 inherits(ShortCurve, Base); +// 将ShortCurve类作为模块对外暴露,方便其他模块使用 module.exports = ShortCurve; +// ShortCurve类的实例方法,用于获取曲线的自同态相关信息(根据传入的配置conf来计算) ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { - // No efficient endomorphism - if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1) + // 如果曲线的参数a不为0,或者没有定义g(可能是曲线上的某个生成元之类的概念),或者没有定义n(可能是曲线相关的阶之类的概念), + // 又或者曲线的参数p(可能是有限域的特征之类的概念)对3取模不等于1,说明不存在有效的自同态,直接返回(不进行后续计算) + if (!this.zeroA ||!this.g ||!this.n || this.p.modn(3)!== 1) return; - // Compute beta and lambda, that lambda * P = (beta * Px; Py) + // 用于存储自同态相关的beta值(具体含义要看对应数学定义),先初始化为undefined var beta; + // 用于存储自同态相关的lambda值(具体含义要看对应数学定义),先初始化为undefined var lambda; if (conf.beta) { + // 如果配置中直接提供了beta值(十六进制表示),将其转换为大整数并转换到蒙哥马利域 beta = new BN(conf.beta, 16).toRed(this.red); } else { + // 如果配置中没有提供beta值,通过调用_getEndoRoots方法计算beta值(具体计算逻辑看该方法实现) var betas = this._getEndoRoots(this.p); - // Choose the smallest beta - beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1]; + // 选择两个beta值中较小的那个,这里通过比较大小来确定 + beta = betas[0].cmp(betas[1]) < 0? betas[0] : betas[1]; beta = beta.toRed(this.red); } if (conf.lambda) { + // 如果配置中直接提供了lambda值(十六进制表示),将其转换为大整数 lambda = new BN(conf.lambda, 16); } else { - // Choose the lambda that is matching selected beta + // 如果配置中没有提供lambda值,通过以下逻辑来确定 + // 先调用_getEndoRoots方法计算lambda的可能取值(基于曲线的参数n) var lambdas = this._getEndoRoots(this.n); + // 根据给定的生成元g以及计算出的beta值,来选择合适的lambda值,通过比较点乘后的横坐标是否相等来判断 if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) { lambda = lambdas[0]; } else { lambda = lambdas[1]; + // 断言验证选择的lambda值是否满足特定的等式关系,若不满足则抛出异常 assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0); } } - // Get basis vectors, used for balanced length-two representation + // 用于存储自同态相关的基向量信息,先初始化为undefined var basis; if (conf.basis) { + // 如果配置中提供了基向量信息(以数组形式,每个元素包含a和b属性),将其转换为相应的大整数形式 basis = conf.basis.map(function(vec) { return { a: new BN(vec.a, 16), @@ -64,9 +89,11 @@ ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { }; }); } else { + // 如果配置中没有提供基向量信息,通过调用_getEndoBasis方法计算基向量(传入lambda值) basis = this._getEndoBasis(lambda); } + // 将计算好的beta、lambda和basis组合成一个对象并返回,作为曲线自同态的相关信息 return { beta: beta, lambda: lambda, @@ -74,27 +101,32 @@ ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) { }; }; +// ShortCurve类的实例方法,用于计算给定数num对应的自同态根(具体是在有限域相关计算的背景下,用于求满足特定方程的根) ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) { - // Find roots of for x^2 + x + 1 in F - // Root = (-1 +- Sqrt(-3)) / 2 - // - var red = num === this.p ? this.red : BN.mont(num); + // 根据传入的数num判断使用哪种蒙哥马利域设置,如果num是曲线的参数p,则使用曲线本身的蒙哥马利域设置this.red,否则创建一个新的蒙哥马利域设置(基于num) + var red = num === this.p? this.red : BN.mont(num); + // 计算2在相应蒙哥马利域内的乘法逆元,用于后续计算 var tinv = new BN(2).toRed(red).redInvm(); + // 计算tinv的相反数(在蒙哥马利域内),同样用于后续计算 var ntinv = tinv.redNeg(); + // 计算方程中根号部分的值,先将3转换为相应蒙哥马利域内的大整数,取相反数后再求平方根,最后乘以tinv(按照方程的数学计算逻辑) var s = new BN(3).toRed(red).redNeg().redSqrt().redMul(tinv); + // 按照方程的计算公式,计算出两个根的值(先进行蒙哥马利域内的运算,再转换为普通整数形式) var l1 = ntinv.redAdd(s).fromRed(); var l2 = ntinv.redSub(s).fromRed(); return [ l1, l2 ]; }; +// ShortCurve类的实例方法,用于计算给定lambda值对应的自同态基向量(具体计算逻辑基于一些数学算法和条件判断) ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { - // aprxSqrt >= sqrt(this.n) + // 计算一个近似的平方根值,用于后续比较和循环判断,这里通过将曲线的参数n右移一定位数来得到(大致是取n的平方根的近似值) var aprxSqrt = this.n.ushrn(Math.floor(this.n.bitLength() / 2)); - // 3.74 - // Run EGCD, until r(L + 1) < aprxSqrt + // 以下代码可能参考了某个编号为3.74的算法或者文档,具体含义要看对应背景知识 + + // 初始化一些变量,用于后续的扩展欧几里得算法(EGCD)相关计算 var u = lambda; var v = this.n.clone(); var x1 = new BN(1); @@ -102,36 +134,44 @@ ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { var x2 = new BN(0); var y2 = new BN(1); - // NOTE: all vectors are roots of: a + b * lambda = 0 (mod n) + // 用于存储计算过程中得到的一些中间向量的系数,先初始化为undefined,具体含义在后续计算中体现 var a0; var b0; - // First vector + // 用于存储第一个基向量的系数,先初始化为undefined var a1; var b1; - // Second vector + // 用于存储第二个基向量的系数,先初始化为undefined var a2; var b2; + // 用于记录上一轮循环计算得到的余数,先初始化为undefined var prevR; var i = 0; var r; var x; - while (u.cmpn(0) !== 0) { + // 循环执行扩展欧几里得算法,直到u变为0(这是EGCD算法的常见终止条件) + while (u.cmpn(0)!== 0) { + // 计算商(v除以u的整数商),用于EGCD算法的步骤 var q = v.div(u); + // 计算余数(v减去q乘以u的结果),同样是EGCD算法的步骤 r = v.sub(q.mul(u)); + // 按照EGCD算法更新x的值 x = x2.sub(q.mul(x1)); var y = y2.sub(q.mul(y1)); + // 如果a1还未赋值(即第一次满足余数小于近似平方根的条件),记录当前的相关系数作为第一个中间向量的系数 if (!a1 && r.cmp(aprxSqrt) < 0) { a0 = prevR.neg(); b0 = x1; a1 = r.neg(); b1 = x; } else if (a1 && ++i === 2) { + // 如果a1已经赋值且已经进行了两次满足条件的循环,跳出循环(表示已经得到了两个基向量相关的系数) break; } prevR = r; + // 更新变量,为下一轮循环做准备,这是EGCD算法中常见的变量更新步骤 v = u; u = r; x2 = x1; @@ -139,108 +179,151 @@ ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) { y2 = y1; y1 = y; } + // 计算并赋值第二个基向量的系数(根据最后一轮循环得到的余数和x值) a2 = r.neg(); b2 = x; + // 计算第一个基向量的长度(按照某种数学定义,这里是通过系数的平方和来计算) var len1 = a1.sqr().add(b1.sqr()); + // 计算第二个基向量的长度(同样按照系数的平方和来计算) var len2 = a2.sqr().add(b2.sqr()); + // 如果第二个基向量的长度大于等于第一个基向量的长度,交换两个基向量的系数(可能是为了选择某种更优的基向量表示) if (len2.cmp(len1) >= 0) { a2 = a0; b2 = b0; } - // Normalize signs + // 对第一个基向量的系数进行符号规范化,如果系数为负数,则取其相反数 if (a1.negative) { a1 = a1.neg(); b1 = b1.neg(); } + // 对第二个基向量的系数进行符号规范化,如果系数为负数,则取其相反数 if (a2.negative) { a2 = a2.neg(); b2 = b2.neg(); } + // 将两个规范化后的基向量以特定的对象形式组成数组并返回,作为自同态的基向量信息 return [ { a: a1, b: b1 }, { a: a2, b: b2 }, ]; }; - +// ShortCurve类的实例方法,用于基于自同态相关的基向量对给定的整数k进行拆分操作 ShortCurve.prototype._endoSplit = function _endoSplit(k) { + // 获取曲线自同态相关的基向量信息(是一个包含两个元素的数组,每个元素包含a和b属性等信息) var basis = this.endo.basis; + // 获取第一个基向量对象 var v1 = basis[0]; + // 获取第二个基向量对象 var v2 = basis[1]; + // 根据特定的数学计算逻辑,计算系数c1,涉及大整数的乘法、除法取整等运算,目的是利用基向量对k进行分解相关的计算 var c1 = v2.b.mul(k).divRound(this.n); + // 同理,计算系数c2,这里取了v1.b的相反数后再进行相应运算 var c2 = v1.b.neg().mul(k).divRound(this.n); + // 按照相关数学逻辑,计算p1,涉及系数c1与基向量v1的a属性的乘法运算(大整数运算) var p1 = c1.mul(v1.a); + // 计算p2,涉及系数c2与基向量v2的a属性的乘法运算 var p2 = c2.mul(v2.a); + // 计算q1,涉及系数c1与基向量v1的b属性的乘法运算 var q1 = c1.mul(v1.b); + // 计算q2,涉及系数c2与基向量v2的b属性的乘法运算 var q2 = c2.mul(v2.b); - // Calculate answer + // 按照特定的计算方式得出k1的值,通过k减去前面计算的p1和p2得到(大整数减法运算) var k1 = k.sub(p1).sub(p2); + // 按照特定的计算方式得出k2的值,通过q1与q2相加后取相反数得到(大整数加法和取相反数运算) var k2 = q1.add(q2).neg(); + + // 将拆分得到的k1和k2以对象形式返回 return { k1: k1, k2: k2 }; }; +// ShortCurve类的实例方法,用于根据横坐标x来创建曲线上的一个点(可能还涉及根据奇偶数情况确定纵坐标等操作) ShortCurve.prototype.pointFromX = function pointFromX(x, odd) { + // 将十六进制表示的横坐标x转换为大整数 x = new BN(x, 16); if (!x.red) + // 如果该大整数还未转换到蒙哥马利域,将其转换到蒙哥马利域(通过曲线相关的设置this.red) x = x.toRed(this.red); + // 按照曲线方程计算纵坐标的平方对应的表达式的值(涉及蒙哥马利域内的乘法、加法等运算) var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b); + // 计算y2的平方根(在蒙哥马利域内),得到纵坐标y的可能值 var y = y2.redSqrt(); - if (y.redSqr().redSub(y2).cmp(this.zero) !== 0) + // 验证计算得到的y的平方减去y2是否等于0(以此验证计算出的y是否符合曲线方程),若不相等则抛出异常,表示点无效 + if (y.redSqr().redSub(y2).cmp(this.zero)!== 0) throw new Error('invalid point'); - // XXX Is there any way to tell if the number is odd without converting it - // to non-red form? + // 以下代码存在疑问注释(XXX开头),意思是想知道是否有办法在不将数转换为非蒙哥马利域形式的情况下判断其奇偶性 + // 目前通过先将y从蒙哥马利域转换出来,再判断其是否为奇数 var isOdd = y.fromRed().isOdd(); - if (odd && !isOdd || !odd && isOdd) + if (odd &&!isOdd ||!odd && isOdd) + // 如果传入的odd参数与实际计算出的y的奇偶性不匹配,将y取相反数(在蒙哥马利域内) y = y.redNeg(); + // 使用横坐标x和最终确定的纵坐标y创建并返回一个曲线上的点对象(通过调用this.point方法) return this.point(x, y); }; +// ShortCurve类的实例方法,用于验证给定的点是否在该曲线上 ShortCurve.prototype.validate = function validate(point) { if (point.inf) + // 如果点是无穷远点(通过point.inf属性判断,具体要看Point类中对该属性的定义),直接返回true,表示无穷远点在曲线上(通常约定俗成) return true; var x = point.x; var y = point.y; + // 按照曲线方程右边部分计算表达式的值,先计算ax(涉及蒙哥马利域内的乘法运算) var ax = this.a.redMul(x); var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b); + // 比较y的平方减去rhs是否等于0(在蒙哥马利域内比较,以此验证点是否满足曲线方程),返回比较结果(0表示相等) return y.redSqr().redISub(rhs).cmpn(0) === 0; }; +// ShortCurve类的实例方法,用于基于自同态窗口非相邻形式(Endomorphism Window NAF,简称_endoWnaf)进行点乘和加法相关的复杂运算 ShortCurve.prototype._endoWnafMulAdd = function _endoWnafMulAdd(points, coeffs, jacobianResult) { + // 获取用于临时存储点相关信息的数组(长度相关等可能在其他地方有设定,从代码看可能用于中间计算存储) var npoints = this._endoWnafT1; + // 获取用于临时存储系数相关信息的数组(同样用于中间计算存储) var ncoeffs = this._endoWnafT2; for (var i = 0; i < points.length; i++) { + // 对每个传入的点对应的系数进行自同态拆分操作(通过调用_endoSplit方法) var split = this._endoSplit(coeffs[i]); var p = points[i]; var beta = p._getBeta(); if (split.k1.negative) { + // 如果拆分得到的k1为负数,取其相反数(大整数取相反数操作) split.k1.ineg(); + // 同时将对应的点p取相反数(可能涉及到曲线上点取相反数的特定逻辑,具体要看相关实现),并传入true参数(具体作用要看对应方法定义) p = p.neg(true); } if (split.k2.negative) { + // 如果拆分得到的k2为负数,取其相反数 split.k2.ineg(); + // 将对应的beta值取相反数(具体含义要看beta代表的数学意义及相关运算要求) beta = beta.neg(true); } + // 将处理后的点p存储到临时点数组npoints中(按照一定的索引规则,这里是间隔存储,可能与后续计算逻辑相关) npoints[i * 2] = p; + // 将处理后的beta值存储到临时点数组npoints中(同样按照索引规则存储) npoints[i * 2 + 1] = beta; + // 将处理后的系数k1存储到临时系数数组ncoeffs中(按照索引规则存储) ncoeffs[i * 2] = split.k1; + // 将处理后的系数k2存储到临时系数数组ncoeffs中(按照索引规则存储) ncoeffs[i * 2 + 1] = split.k2; } + // 调用_wnafMulAdd方法进行进一步的点乘和加法相关计算(传入多个参数,具体含义要看该方法的定义及功能),并获取结果 var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2, jacobianResult); - // Clean-up references to points and coefficients + // 清理临时点数组和临时系数数组中的引用,将元素置为null,释放内存或者避免后续不必要的引用问题 for (var j = 0; j < i * 2; j++) { npoints[j] = null; ncoeffs[j] = null; @@ -248,45 +331,59 @@ ShortCurve.prototype._endoWnafMulAdd = return res; }; +// Point类的构造函数,用于创建曲线上的一个点对象,继承自Base.BasePoint类(具体功能要看Base.BasePoint的定义) function Point(curve, x, y, isRed) { + // 调用Base.BasePoint类的构造函数,传入曲线类型和'affine'标识,具体作用看其定义 Base.BasePoint.call(this, curve, 'affine'); if (x === null && y === null) { + // 如果传入的横坐标x和纵坐标y都为null,将点的横坐标、纵坐标设为null,并标记该点为无穷远点(通过inf属性设为true) this.x = null; this.y = null; this.inf = true; } else { + // 将十六进制表示的横坐标x转换为大整数 this.x = new BN(x, 16); + // 将十六进制表示的纵坐标y转换为大整数 this.y = new BN(y, 16); - // Force redgomery representation when loading from JSON + // 如果传入的isRed参数为true,表示要强制将坐标转换为蒙哥马利域表示(可能在从JSON数据等加载点信息时需要确保这种表示形式) if (isRed) { this.x.forceRed(this.curve.red); this.y.forceRed(this.curve.red); } if (!this.x.red) + // 如果横坐标的大整数还未转换到蒙哥马利域,进行转换(通过曲线的相关设置this.curve.red) this.x = this.x.toRed(this.curve.red); if (!this.y.red) + // 同理,对纵坐标进行转换到蒙哥马利域的操作 this.y = this.y.toRed(this.curve.red); this.inf = false; } } +// 实现Point类继承自Base.BasePoint类的继承关系 inherits(Point, Base.BasePoint); +// ShortCurve类的实例方法,用于创建一个曲线上的点对象,传入横坐标x、纵坐标y以及是否强制转换为蒙哥马利域表示的标志isRed(可选参数) ShortCurve.prototype.point = function point(x, y, isRed) { return new Point(this, x, y, isRed); }; +// ShortCurve类的实例方法,用于从JSON数据创建一个曲线上的点对象,传入JSON数据对象obj以及是否强制转换为蒙哥马利域表示的标志red(可选参数) ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) { return Point.fromJSON(this, obj, red); }; +// Point类的实例方法,用于获取与该点相关的beta值(具体含义要看在曲线自同态相关的数学定义及应用场景中beta的作用) Point.prototype._getBeta = function _getBeta() { if (!this.curve.endo) + // 如果曲线没有定义自同态相关信息(通过this.curve.endo判断,具体在ShortCurve类中设置),直接返回(不进行后续计算) return; var pre = this.precomputed; if (pre && pre.beta) + // 如果点已经有预计算的beta值(通过pre.beta判断,具体要看pre对象的结构及设置逻辑),直接返回该预计算的值 return pre.beta; + // 根据曲线的自同态beta值以及当前点的横坐标,创建一个新的点对象作为beta(具体数学意义可能是与自同态映射相关) var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y); if (pre) { var curve = this.curve; @@ -297,10 +394,12 @@ Point.prototype._getBeta = function _getBeta() { beta.precomputed = { beta: null, naf: pre.naf && { + // 如果点有预计算的非相邻形式(NAF)相关信息,复制其窗口宽度wnd属性,并对其存储的点列表进行映射操作(通过endoMul函数) wnd: pre.naf.wnd, points: pre.naf.points.map(endoMul), }, doubles: pre.doubles && { + // 如果点有预计算的加倍相关信息,复制其步长step属性,并对其存储的点列表进行映射操作(通过endoMul函数) step: pre.doubles.step, points: pre.doubles.points.map(endoMul), }, @@ -308,7 +407,6 @@ Point.prototype._getBeta = function _getBeta() { } return beta; }; - Point.prototype.toJSON = function toJSON() { if (!this.precomputed) return [ this.x, this.y ]; -- 2.34.1 From aac8866aa8d81699ff32d3b79795841d76fbe2d5 Mon Sep 17 00:00:00 2001 From: yangzhen <3104844212@qq.com> Date: Tue, 17 Dec 2024 14:58:09 +0800 Subject: [PATCH 2/2] 11 --- .../elliptic/lib/elliptic/curve/short.js | 380 ++++++++++++++---- 1 file changed, 311 insertions(+), 69 deletions(-) diff --git a/node_modules/elliptic/lib/elliptic/curve/short.js b/node_modules/elliptic/lib/elliptic/curve/short.js index ae58df6..1f795c3 100644 --- a/node_modules/elliptic/lib/elliptic/curve/short.js +++ b/node_modules/elliptic/lib/elliptic/curve/short.js @@ -407,30 +407,40 @@ Point.prototype._getBeta = function _getBeta() { } return beta; }; +// Point类的实例方法,用于将点对象转换为JSON可序列化的格式(通常用于数据存储、传输等场景) Point.prototype.toJSON = function toJSON() { if (!this.precomputed) + // 如果点对象没有预计算相关的数据(通过precomputed属性判断,具体看其定义及赋值情况),直接返回包含横坐标x和纵坐标y的数组作为JSON表示形式 return [ this.x, this.y ]; return [ this.x, this.y, this.precomputed && { doubles: this.precomputed.doubles && { + // 如果有点的预计算加倍相关信息(通过precomputed.doubles判断),提取加倍信息中的步长step属性 step: this.precomputed.doubles.step, + // 提取加倍信息中存储的点列表,但去掉第一个元素(通过slice(1)操作),可能是因为第一个元素有特殊处理或者不需要包含在JSON表示中,具体要看业务逻辑 points: this.precomputed.doubles.points.slice(1), }, naf: this.precomputed.naf && { + // 如果有点的预计算非相邻形式(NAF)相关信息(通过precomputed.naf判断),提取NAF信息中的窗口宽度wnd属性 wnd: this.precomputed.naf.wnd, + // 提取NAF信息中存储的点列表,但去掉第一个元素(通过slice(1)操作),原因同doubles情况类似 points: this.precomputed.naf.points.slice(1), }, } ]; }; +// Point类的静态方法,用于从JSON数据反序列化创建一个Point对象,传入曲线对象curve、JSON数据obj以及是否强制转换为蒙哥马利域表示的标志red(可选参数) Point.fromJSON = function fromJSON(curve, obj, red) { - if (typeof obj === 'string') + if (typeof obj ==='string') + // 如果传入的obj是字符串形式,先将其解析为JSON对象(通过JSON.parse方法) obj = JSON.parse(obj); var res = curve.point(obj[0], obj[1], red); if (!obj[2]) + // 如果JSON数据中没有第三个元素(可能对应包含预计算信息的部分),直接返回创建好的点对象res return res; function obj2point(obj) { + // 内部函数,用于将包含坐标信息的数组转换为曲线上的点对象,通过调用curve.point方法创建,传入坐标及是否强制转换为蒙哥马利域表示的标志red return curve.point(obj[0], obj[1], red); } @@ -438,125 +448,163 @@ Point.fromJSON = function fromJSON(curve, obj, red) { res.precomputed = { beta: null, doubles: pre.doubles && { + // 如果JSON数据中的预计算加倍信息存在(通过pre.doubles判断),提取步长step属性 step: pre.doubles.step, + // 创建一个新的点列表,将当前点res作为第一个元素,然后将预计算加倍信息中的点列表通过obj2point函数转换后拼接起来,形成完整的加倍相关的点列表 points: [ res ].concat(pre.doubles.points.map(obj2point)), }, naf: pre.naf && { + // 如果JSON数据中的预计算NAF信息存在(通过pre.naf判断),提取窗口宽度wnd属性 wnd: pre.naf.wnd, + // 创建一个新的点列表,将当前点res作为第一个元素,然后将预计算NAF信息中的点列表通过obj2point函数转换后拼接起来,形成完整的NAF相关的点列表 points: [ res ].concat(pre.naf.points.map(obj2point)), }, }; return res; }; +// Point类的实例方法,用于返回点对象的字符串表示形式,方便调试等查看操作 Point.prototype.inspect = function inspect() { if (this.isInfinity()) + // 如果点是无穷远点(通过isInfinity方法判断,具体看其实现),返回表示无穷远点的字符串形式 return ''; return ''; }; +// Point类的实例方法,用于判断点是否为无穷远点,直接返回inf属性的值(该属性在Point类的构造函数等地方进行赋值,用于标记点是否为无穷远点) Point.prototype.isInfinity = function isInfinity() { return this.inf; }; +// Point类的实例方法,用于实现两个点的加法操作,按照椭圆曲线点加法的相关数学规则及逻辑来实现 Point.prototype.add = function add(p) { - // O + P = P + // 如果当前点是无穷远点,根据椭圆曲线加法规则,无穷远点加任何点等于那个点本身,所以直接返回传入的点p if (this.inf) return p; - // P + O = P + // 如果传入的点p是无穷远点,根据规则,任何点加无穷远点等于该点本身,所以直接返回当前点this if (p.inf) return this; - // P + P = 2P + // 如果当前点和传入的点p相等,根据椭圆曲线加法规则,点加自身等于该点的加倍操作,所以调用dbl方法进行加倍并返回结果 if (this.eq(p)) return this.dbl(); - // P + (-P) = O + // 如果当前点是传入点p的相反数(通过neg方法取相反数后比较是否相等来判断),根据规则,点加其相反数等于无穷远点,所以返回表示无穷远点的点对象(通过调用this.curve.point(null, null)创建) if (this.neg().eq(p)) return this.curve.point(null, null); - // P + Q = O + // 如果当前点和传入点p的横坐标相等,根据椭圆曲线规则,在某些情况下这样的两个点相加结果是无穷远点,所以返回表示无穷远点的点对象 if (this.x.cmp(p.x) === 0) return this.curve.point(null, null); + // 按照椭圆曲线点加法的数学计算公式,先计算c,即两点纵坐标之差除以横坐标之差的乘法逆元(在蒙哥马利域内进行相关运算) var c = this.y.redSub(p.y); - if (c.cmpn(0) !== 0) + if (c.cmpn(0)!== 0) c = c.redMul(this.x.redSub(p.x).redInvm()); + // 计算新的横坐标nx,按照特定的数学公式进行蒙哥马利域内的运算 var nx = c.redSqr().redISub(this.x).redISub(p.x); + // 计算新的纵坐标ny,同样按照相应数学公式进行蒙哥马利域内的运算 var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); return this.curve.point(nx, ny); }; +// Point类的实例方法,用于实现点的加倍操作,按照椭圆曲线点加倍的相关数学规则及逻辑来实现 Point.prototype.dbl = function dbl() { if (this.inf) + // 如果当前点是无穷远点,根据规则,无穷远点加倍还是无穷远点,所以直接返回当前点 return this; - // 2P = O + // 按照椭圆曲线点加倍的数学计算公式,先计算ys1,即纵坐标的两倍(在蒙哥马利域内进行运算),如果ys1为0,根据规则,加倍结果是无穷远点,返回表示无穷远点的点对象 var ys1 = this.y.redAdd(this.y); if (ys1.cmpn(0) === 0) return this.curve.point(null, null); var a = this.curve.a; + // 计算横坐标的平方(在蒙哥马利域内) var x2 = this.x.redSqr(); + // 计算ys1的乘法逆元(在蒙哥马利域内),用于后续计算 var dyinv = ys1.redInvm(); + // 按照特定的数学公式计算c,涉及蒙哥马利域内的乘法、加法等运算 var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv); + // 计算新的横坐标nx,按照相应数学公式进行蒙哥马利域内的运算 var nx = c.redSqr().redISub(this.x.redAdd(this.x)); + // 计算新的纵坐标ny,同样按照相应数学公式进行蒙哥马利域内的运算 var ny = c.redMul(this.x.redSub(nx)).redISub(this.y); return this.curve.point(nx, ny); }; +// Point类的实例方法,用于获取点对象的横坐标(从蒙哥马利域转换为普通表示形式后返回) Point.prototype.getX = function getX() { return this.x.fromRed(); }; +// Point类的实例方法,用于获取点对象的纵坐标(从蒙哥马利域转换为普通表示形式后返回) Point.prototype.getY = function getY() { return this.y.fromRed(); }; +// Point类的实例方法,用于实现点乘操作,根据不同条件选择不同的点乘计算方式 Point.prototype.mul = function mul(k) { k = new BN(k, 16); if (this.isInfinity()) + // 如果当前点是无穷远点,根据规则,无穷远点与任何数相乘还是无穷远点,所以直接返回当前点 return this; else if (this._hasDoubles(k)) + // 如果满足某种条件(通过调用_hasDoubles方法判断,具体看其实现),调用曲线对象的_fixedNafMul方法进行点乘计算(传入当前点和乘数k) return this.curve._fixedNafMul(this, k); else if (this.curve.endo) + // 如果曲线对象有自同态相关信息(通过this.curve.endo判断),调用曲线对象的_endoWnafMulAdd方法进行点乘计算(传入包含当前点的数组和包含乘数k的数组) return this.curve._endoWnafMulAdd([ this ], [ k ]); else + // 如果以上条件都不满足,调用曲线对象的_wnafMul方法进行点乘计算(传入当前点和乘数k) return this.curve._wnafMul(this, k); }; - +// Point类的实例方法,用于实现点乘后再与另一个点进行加法的复合操作(mulAdd通常在一些密码学相关计算中用于优化计算流程等场景) Point.prototype.mulAdd = function mulAdd(k1, p2, k2) { + // 创建一个包含当前点和传入的另一个点p2的数组,用于后续统一处理 var points = [ this, p2 ]; + // 创建一个包含两个乘数k1和k2的数组,对应前面points数组中点的系数 var coeffs = [ k1, k2 ]; if (this.curve.endo) + // 如果曲线对象有自同态相关信息(通过this.curve.endo判断),调用曲线对象的_endoWnafMulAdd方法进行基于自同态窗口非相邻形式(Endomorphism Window NAF)的点乘和加法相关计算,传入点数组和系数数组 return this.curve._endoWnafMulAdd(points, coeffs); else + // 如果曲线对象没有自同态相关信息,调用曲线对象的_wnafMulAdd方法进行常规的点乘和加法相关计算,传入一些固定参数(这里传入1、点数组、系数数组以及表示数组长度的2) return this.curve._wnafMulAdd(1, points, coeffs, 2); }; +// Point类的实例方法,功能与mulAdd类似,但可能在具体实现或使用场景上有细微差别(从函数名看可能是某种特定的点乘加操作,也许与Jacobian坐标等相关,具体要看代码上下文及应用场景) Point.prototype.jmulAdd = function jmulAdd(k1, p2, k2) { var points = [ this, p2 ]; var coeffs = [ k1, k2 ]; if (this.curve.endo) + // 如果曲线对象有自同态相关信息,调用曲线对象的_endoWnafMulAdd方法进行相关计算,传入点数组、系数数组以及一个额外的参数true(具体作用要看_endoWnafMulAdd方法内部对该参数的处理逻辑) return this.curve._endoWnafMulAdd(points, coeffs, true); else + // 如果曲线对象没有自同态相关信息,调用曲线对象的_wnafMulAdd方法进行相关计算,传入固定参数(与mulAdd调用类似,但同样多传入一个额外的参数true) return this.curve._wnafMulAdd(1, points, coeffs, 2, true); }; +// Point类的实例方法,用于比较当前点与传入的点p是否相等,根据点的相关属性及坐标值进行比较判断 Point.prototype.eq = function eq(p) { return this === p || - this.inf === p.inf && - (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0); + // 首先判断两点是否为同一个对象引用(通过 === 比较),如果不是,再进一步比较以下属性 + this.inf === p.inf && + // 先比较两点的inf属性(用于标记是否为无穷远点)是否相等,如果都不是无穷远点(即this.inf为false),再比较横坐标和纵坐标是否分别相等 + (this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0); }; +// Point类的实例方法,用于获取当前点的相反数(在椭圆曲线的数学概念中,每个点都有对应的相反数) Point.prototype.neg = function neg(_precompute) { if (this.inf) + // 如果当前点是无穷远点,根据椭圆曲线的性质,无穷远点的相反数还是无穷远点,所以直接返回当前点 return this; + // 创建一个新的点对象,横坐标与当前点相同,纵坐标取当前点纵坐标的相反数(在蒙哥马利域内通过redNeg方法取反) var res = this.curve.point(this.x, this.y.redNeg()); if (_precompute && this.precomputed) { var pre = this.precomputed; @@ -565,10 +613,12 @@ Point.prototype.neg = function neg(_precompute) { }; res.precomputed = { naf: pre.naf && { + // 如果当前点有预计算的非相邻形式(NAF)相关信息(通过pre.naf判断),复制其窗口宽度wnd属性,并对其存储的点列表中的每个点调用negate函数(即取相反数操作)来更新点列表 wnd: pre.naf.wnd, points: pre.naf.points.map(negate), }, doubles: pre.doubles && { + // 如果当前点有预计算的加倍相关信息(通过pre.doubles判断),复制其步长step属性,并对其存储的点列表中的每个点调用negate函数来更新点列表 step: pre.doubles.step, points: pre.doubles.points.map(negate), }, @@ -577,316 +627,409 @@ Point.prototype.neg = function neg(_precompute) { return res; }; +// Point类的实例方法,用于将当前点转换为某种特定的表示形式(从函数名toJ推测可能是转换到Jacobian坐标形式之类的,具体要看相关代码上下文及应用场景) Point.prototype.toJ = function toJ() { if (this.inf) + // 如果当前点是无穷远点,调用曲线对象的jpoint方法创建并返回对应的无穷远点的特定表示形式(传入null等参数,具体看jpoint方法实现) return this.curve.jpoint(null, null, null); + // 调用曲线对象的jpoint方法,传入当前点的横坐标、纵坐标以及曲线的单位元(通过this.curve.one获取),创建并返回对应的特定表示形式的点对象 var res = this.curve.jpoint(this.x, this.y, this.curve.one); return res; }; +// JPoint类的构造函数,用于创建一种特定表示形式(可能是Jacobian坐标形式,从继承关系及函数名等推测)的点对象,继承自Base.BasePoint类(具体功能要看Base.BasePoint的定义) function JPoint(curve, x, y, z) { + // 调用Base.BasePoint类的构造函数,传入曲线类型和'jacobian'标识,具体作用看其定义 Base.BasePoint.call(this, curve, 'jacobian'); if (x === null && y === null && z === null) { + // 如果传入的横坐标x、纵坐标y和竖坐标z都为null,将横坐标和纵坐标设为曲线的单位元(通过this.curve.one获取),将竖坐标设为0(通过创建大整数0来表示) this.x = this.curve.one; this.y = this.curve.one; this.z = new BN(0); } else { + // 将十六进制表示的横坐标x转换为大整数 this.x = new BN(x, 16); + // 将十六进制表示的纵坐标y转换为大整数 this.y = new BN(y, 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.y.red) + // 同理,对纵坐标进行转换到蒙哥马利域的操作 this.y = this.y.toRed(this.curve.red); if (!this.z.red) + // 同理,对竖坐标进行转换到蒙哥马利域的操作 this.z = this.z.toRed(this.curve.red); + // 判断竖坐标是否等于曲线的单位元,将结果保存在zOne属性中,可能用于后续一些针对该特殊情况的优化判断等操作 this.zOne = this.z === this.curve.one; } +// 实现JPoint类继承自Base.BasePoint类的继承关系 inherits(JPoint, Base.BasePoint); +// ShortCurve类的实例方法,用于创建一个JPoint对象(即特定表示形式的点对象,推测是Jacobian坐标形式),传入横坐标x、纵坐标y和竖坐标z(可选参数,可为null等) ShortCurve.prototype.jpoint = function jpoint(x, y, z) { return new JPoint(this, x, y, z); }; +// JPoint类的实例方法,用于将当前的特定表示形式(如Jacobian坐标形式)的点转换为常规的坐标表示形式的点(从函数名toP推测) JPoint.prototype.toP = function toP() { if (this.isInfinity()) + // 如果当前点是无穷远点(通过isInfinity方法判断,具体看其实现),调用曲线对象的point方法创建并返回表示无穷远点的常规坐标表示形式的点对象(传入null等参数) return this.curve.point(null, null); + // 计算竖坐标的乘法逆元(在蒙哥马利域内通过redInvm方法计算),用于后续坐标转换计算 var zinv = this.z.redInvm(); + // 计算竖坐标逆元的平方(在蒙哥马利域内) var zinv2 = zinv.redSqr(); + // 按照坐标转换的数学公式,计算转换后的横坐标ax,涉及蒙哥马利域内的乘法运算 var ax = this.x.redMul(zinv2); + // 按照坐标转换的数学公式,计算转换后的纵坐标ay,涉及蒙哥马利域内的乘法、乘法逆元相关运算 var ay = this.y.redMul(zinv2).redMul(zinv); + // 调用曲线对象的point方法,传入转换后的横坐标ax和纵坐标ay,创建并返回常规坐标表示形式的点对象 return this.curve.point(ax, ay); }; +// JPoint类的实例方法,用于获取当前特定表示形式(如Jacobian坐标形式)的点的相反数 JPoint.prototype.neg = function neg() { + // 调用曲线对象的jpoint方法,传入当前点的横坐标、纵坐标取相反数(在蒙哥马利域内通过redNeg方法对纵坐标取反)以及竖坐标,创建并返回表示相反数的特定表示形式的点对象 return this.curve.jpoint(this.x, this.y.redNeg(), this.z); }; +// JPoint类的实例方法,用于实现两个特定表示形式(如Jacobian坐标形式)的点的加法操作,按照相应的数学规则及逻辑来实现 JPoint.prototype.add = function add(p) { - // O + P = P + // 如果当前点是无穷远点,根据椭圆曲线加法规则,无穷远点加任何点等于那个点本身,所以直接返回传入的点p if (this.isInfinity()) return p; - // P + O = P + // 如果传入的点p是无穷远点,根据规则,任何点加无穷远点等于该点本身,所以直接返回当前点this if (p.isInfinity()) return this; + // 以下注释中的12M + 4S + 7A可能是表示此加法操作在底层实现中大致涉及的乘法(M)、平方(S)和加法(A)的次数,用于性能评估等参考 // 12M + 4S + 7A + + // 计算传入点p的竖坐标的平方(在蒙哥马利域内) var pz2 = p.z.redSqr(); + // 计算当前点的竖坐标的平方(在蒙哥马利域内) var z2 = this.z.redSqr(); + // 按照特定的数学计算公式,计算u1,涉及蒙哥马利域内的乘法运算 var u1 = this.x.redMul(pz2); + // 按照相应公式,计算u2,同样涉及蒙哥马利域内的乘法运算 var u2 = p.x.redMul(z2); + // 按照相应公式,计算s1,涉及蒙哥马利域内的乘法、乘法结合(连续乘法)等运算 var s1 = this.y.redMul(pz2.redMul(p.z)); + // 按照相应公式,计算s2,同样涉及蒙哥马利域内的乘法、乘法结合等运算 var s2 = p.y.redMul(z2.redMul(this.z)); + // 计算h,即u1与u2的差(在蒙哥马利域内) var h = u1.redSub(u2); + // 计算r,即s1与s2的差(在蒙哥马利域内) var r = s1.redSub(s2); if (h.cmpn(0) === 0) { - if (r.cmpn(0) !== 0) + if (r.cmpn(0)!== 0) + // 如果h为0但r不为0,根据椭圆曲线相关规则,相加结果是无穷远点,调用曲线对象的jpoint方法创建并返回表示无穷远点的特定表示形式的点对象(传入null等参数) return this.curve.jpoint(null, null, null); else + // 如果h和r都为0,说明两点相等,根据规则,点加自身等于该点的加倍操作,调用dbl方法进行加倍并返回结果(具体看dbl方法的实现,应该是针对JPoint类型点的加倍操作) return this.dbl(); } + // 计算h的平方(在蒙哥马利域内) var h2 = h.redSqr(); + // 计算h的立方(在蒙哥马利域内,通过先计算平方再乘以h实现) var h3 = h2.redMul(h); + // 按照相应公式,计算v,涉及蒙哥马利域内的乘法运算 var v = u1.redMul(h2); + // 按照特定的数学公式,计算新的横坐标nx,涉及蒙哥马利域内的加法、减法等运算 var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); + // 按照相应公式,计算新的纵坐标ny,涉及蒙哥马利域内的乘法、减法等运算 var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + // 按照相应公式,计算新的竖坐标nz,涉及蒙哥马利域内的乘法运算 var nz = this.z.redMul(p.z).redMul(h); + // 调用曲线对象的jpoint方法,传入新计算的横坐标nx、纵坐标ny和竖坐标nz,创建并返回表示相加结果的特定表示形式的点对象 return this.curve.jpoint(nx, ny, nz); }; - +// JPoint类的实例方法,用于实现混合加法操作,即将当前的JPoint(可能是某种特定坐标表示形式,如Jacobian坐标形式)与另一个点进行加法运算, +// 这里的“混合”可能意味着另一个点的坐标表示形式与当前点有所不同,按照相应的数学规则来实现该加法操作。 JPoint.prototype.mixedAdd = function mixedAdd(p) { - // O + P = P + // 如果当前点是无穷远点,根据椭圆曲线加法规则,无穷远点加任何点等于那个点转换为当前点相同的表示形式(这里是通过调用toJ方法转换为JPoint形式),所以返回传入点p转换后的形式。 if (this.isInfinity()) return p.toJ(); - // P + O = P + // 如果传入的点p是无穷远点,根据规则,任何点加无穷远点等于该点本身,所以直接返回当前点this。 if (p.isInfinity()) return this; + // 以下注释中的8M + 3S + 7A可能是表示此混合加法操作在底层实现中大致涉及的乘法(M)、平方(S)和加法(A)的次数,用于性能评估等参考。 // 8M + 3S + 7A + + // 计算当前点竖坐标的平方(在蒙哥马利域内进行运算),用于后续相关计算。 var z2 = this.z.redSqr(); + // 将当前点的横坐标直接赋值给u1,作为后续计算的一个中间变量(按照特定的数学计算逻辑)。 var u1 = this.x; + // 按照相应的计算公式,计算u2,涉及传入点p的横坐标与当前点竖坐标平方的乘法运算(在蒙哥马利域内)。 var u2 = p.x.redMul(z2); + // 将当前点的纵坐标直接赋值给s1,作为后续计算的一个中间变量。 var s1 = this.y; + // 按照相应的计算公式,计算s2,涉及传入点p的纵坐标、当前点竖坐标平方以及当前点竖坐标的乘法运算(在蒙哥马利域内)。 var s2 = p.y.redMul(z2).redMul(this.z); + // 计算h,即u1与u2的差(在蒙哥马利域内进行减法运算),用于后续判断和进一步计算。 var h = u1.redSub(u2); + // 计算r,即s1与s2的差(在蒙哥马利域内进行减法运算),同样用于后续判断和计算。 var r = s1.redSub(s2); if (h.cmpn(0) === 0) { - if (r.cmpn(0) !== 0) + if (r.cmpn(0)!== 0) + // 如果h为0但r不为0,根据椭圆曲线相关规则,相加结果是无穷远点,调用曲线对象的jpoint方法创建并返回表示无穷远点的特定表示形式的点对象(传入null等参数)。 return this.curve.jpoint(null, null, null); else + // 如果h和r都为0,说明两点相等,根据规则,点加自身等于该点的加倍操作,调用dbl方法进行加倍并返回结果(具体看dbl方法的实现,应该是针对JPoint类型点的加倍操作)。 return this.dbl(); } + // 计算h的平方(在蒙哥马利域内进行平方运算),用于后续按照数学公式计算新的坐标值。 var h2 = h.redSqr(); + // 计算h的立方(在蒙哥马利域内,通过先计算平方再乘以h实现),同样是后续计算新坐标的一部分。 var h3 = h2.redMul(h); + // 按照相应的数学公式,计算v,涉及蒙哥马利域内的乘法运算。 var v = u1.redMul(h2); + // 按照特定的数学公式,计算新的横坐标nx,涉及蒙哥马利域内的加法、减法等运算。 var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v); + // 按照相应的数学公式,计算新的纵坐标ny,涉及蒙哥马利域内的乘法、减法等运算。 var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3)); + // 按照相应的数学公式,计算新的竖坐标nz,涉及蒙哥马利域内的乘法运算。 var nz = this.z.redMul(h); + // 调用曲线对象的jpoint方法,传入新计算的横坐标nx、纵坐标ny和竖坐标nz,创建并返回表示相加结果的特定表示形式的点对象。 return this.curve.jpoint(nx, ny, nz); }; +// JPoint类的实例方法,用于实现点的多次加倍操作,根据传入的幂次pow来决定对当前点进行多少次加倍运算。 JPoint.prototype.dblp = function dblp(pow) { if (pow === 0) + // 如果幂次pow为0,根据数学意义,任何点的0次加倍还是其本身,所以直接返回当前点this。 return this; if (this.isInfinity()) + // 如果当前点是无穷远点,无穷远点无论进行多少次加倍操作还是无穷远点,所以直接返回当前点this。 return this; if (!pow) + // 如果pow为假值(可能是0、null、undefined等情况,这里应该是表示默认进行一次加倍操作的情况),调用dbl方法进行一次加倍操作并返回结果(具体看dbl方法的实现)。 return this.dbl(); var i; if (this.curve.zeroA || this.curve.threeA) { var r = this; for (i = 0; i < pow; i++) + // 如果曲线满足特定条件(通过this.curve.zeroA或this.curve.threeA判断,具体含义要看这两个属性在曲线类中的定义及表示的曲线特性), + // 通过循环多次调用dbl方法来实现多次加倍操作,每次循环都更新中间点对象r,最终返回经过多次加倍后的点对象r。 r = r.dbl(); return r; } + // 以下注释中的1M + 2S + 1A + N * (4S + 5M + 8A)可能是表示此加倍操作在底层实现中大致涉及的不同运算次数以及与幂次N相关的复杂度描述, + // N = 1 => 6M + 6S + 9A表示当幂次N为1时具体的运算次数情况,用于性能评估等参考。 // 1M + 2S + 1A + N * (4S + 5M + 8A) // N = 1 => 6M + 6S + 9A + + // 获取曲线对象的参数a(具体含义要看曲线相关的数学定义及在代码中的应用场景)。 var a = this.curve.a; + // 获取曲线对象的某个与计算相关的系数tinv(具体含义及用途要看其在曲线相关计算中的定义)。 var tinv = this.curve.tinv; + // 将当前点的横坐标、纵坐标、竖坐标分别赋值给相应变量,作为后续计算的初始值。 var jx = this.x; var jy = this.y; var jz = this.z; + // 计算当前点竖坐标的四次方(通过先计算平方再对平方结果计算平方来实现,在蒙哥马利域内进行运算),用于后续相关计算。 var jz4 = jz.redSqr().redSqr(); - // Reuse results + // 以下循环用于实现多次加倍操作(幂次大于1且曲线不满足前面特定条件的情况),每次循环进行一次加倍的相关计算并更新坐标值。 + // 重用一些中间计算结果,这里将当前点纵坐标加倍后赋值给jyd,方便后续循环中多次使用(避免重复计算)。 var jyd = jy.redAdd(jy); for (i = 0; i < pow; i++) { + // 计算当前点横坐标的平方(在蒙哥马利域内进行运算),作为后续计算的一部分。 var jx2 = jx.redSqr(); + // 计算jyd(纵坐标加倍后的值)的平方(在蒙哥马利域内进行运算),用于后续按照数学公式计算新的坐标值。 var jyd2 = jyd.redSqr(); + // 计算jyd2的平方,即纵坐标加倍后值的四次方(在蒙哥马利域内进行运算),同样用于后续计算。 var jyd4 = jyd2.redSqr(); + // 按照特定的数学公式,计算c,涉及横坐标平方的相关运算以及曲线参数a与竖坐标四次方的乘法运算(在蒙哥马利域内),用于后续计算新坐标。 var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); + // 按照相应的数学公式,计算t1,涉及横坐标与jyd2的乘法运算(在蒙哥马利域内),用于后续计算新坐标。 var t1 = jx.redMul(jyd2); + // 按照特定的数学公式,计算新的横坐标nx,涉及蒙哥马利域内的加法、减法等运算。 var nx = c.redSqr().redISub(t1.redAdd(t1)); + // 按照相应的数学公式,计算t2,涉及t1与nx的减法运算(在蒙哥马利域内),用于后续计算新的纵坐标。 var t2 = t1.redISub(nx); + // 按照相应的数学公式,计算新的纵坐标dny,涉及蒙哥马利域内的乘法、加法、减法等运算,先计算乘法部分,然后通过一些加法和减法调整结果。 var dny = c.redMul(t2); dny = dny.redIAdd(dny).redISub(jyd4); + // 按照相应的数学公式,计算新的竖坐标nz,涉及纵坐标加倍后的值与竖坐标的乘法运算(在蒙哥马利域内)。 var nz = jyd.redMul(jz); if (i + 1 < pow) + // 如果还未完成所有指定幂次的加倍操作(下一次循环还需要继续加倍),更新jz4的值,用于下一轮循环中的相关计算(通过乘以jyd4来更新)。 jz4 = jz4.redMul(jyd4); + // 更新横坐标、竖坐标以及纵坐标加倍后的值,为下一轮循环做准备,这样不断循环实现多次加倍操作。 jx = nx; jz = nz; jyd = dny; } + // 调用曲线对象的jpoint方法,传入最终计算得到的横坐标jx、纵坐标经过一定调整(乘以tinv)后的结果以及竖坐标jz,创建并返回经过多次加倍操作后的特定表示形式的点对象。 return this.curve.jpoint(jx, jyd.redMul(tinv), jz); }; +// JPoint类的实例方法,用于实现点的加倍操作,根据曲线的不同特性(通过判断曲线相关属性this.curve.zeroA和this.curve.threeA)选择不同的加倍实现方式。 JPoint.prototype.dbl = function dbl() { if (this.isInfinity()) + // 如果当前点是无穷远点,根据规则,无穷远点加倍还是无穷远点,所以直接返回当前点this。 return this; if (this.curve.zeroA) + // 如果曲线满足特定条件(通过this.curve.zeroA判断,具体含义要看其在曲线类中的定义及表示的曲线特性),调用_zeroDbl方法进行加倍操作并返回结果(具体看_zeroDbl方法的实现)。 return this._zeroDbl(); else if (this.curve.threeA) + // 如果曲线满足另一种特定条件(通过this.curve.threeA判断),调用_threeDbl方法进行加倍操作并返回结果(具体看_threeDbl方法的实现)。 return this._threeDbl(); else + // 如果曲线不满足前面两种特定条件,调用_dbl方法进行加倍操作并返回结果(具体看_dbl方法的实现)。 return this._dbl(); }; - +// JPoint类的实例方法,用于在特定曲线条件(this.curve.zeroA为真)下计算点的加倍操作,根据点的坐标表示形式(this.zOne是否为真)有不同的计算方式。 JPoint.prototype._zeroDbl = function _zeroDbl() { var nx; var ny; var nz; - // Z = 1 + // Z = 1,表示点在某种特定情况下(可能是竖坐标为1的简化表示形式)的加倍计算 if (this.zOne) { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html - // #doubling-mdbl-2007-bl - // 1M + 5S + 14A + // 参考特定的文档链接(hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl)进行计算 + // 1M + 5S + 14A,表示此计算过程中大致涉及的乘法(M)、平方(S)和加法(A)的次数,用于性能评估等参考 - // XX = X1^2 + // XX = X1^2,计算横坐标的平方(在蒙哥马利域内进行运算) var xx = this.x.redSqr(); - // YY = Y1^2 + // YY = Y1^2,计算纵坐标的平方 var yy = this.y.redSqr(); - // YYYY = YY^2 + // YYYY = YY^2,计算纵坐标平方的平方 var yyyy = yy.redSqr(); - // S = 2 * ((X1 + YY)^2 - XX - YYYY) + // S = 2 * ((X1 + YY)^2 - XX - YYYY),按照特定数学公式计算S,涉及蒙哥马利域内的加法、平方、减法等运算 var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); s = s.redIAdd(s); - // M = 3 * XX + a; a = 0 + // M = 3 * XX + a; a = 0,由于a为0,简化为计算横坐标平方的三倍 var m = xx.redAdd(xx).redIAdd(xx); - // T = M ^ 2 - 2*S + // T = M ^ 2 - 2*S,按照公式计算T,涉及平方和减法运算 var t = m.redSqr().redISub(s).redISub(s); - // 8 * YYYY + // 8 * YYYY,通过多次加法计算纵坐标平方的平方的8倍(在蒙哥马利域内) var yyyy8 = yyyy.redIAdd(yyyy); yyyy8 = yyyy8.redIAdd(yyyy8); yyyy8 = yyyy8.redIAdd(yyyy8); - // X3 = T + // X3 = T,新的横坐标等于T nx = t; - // Y3 = M * (S - T) - 8 * YYYY + // Y3 = M * (S - T) - 8 * YYYY,按照公式计算新的纵坐标,涉及乘法、减法等运算 ny = m.redMul(s.redISub(t)).redISub(yyyy8); - // Z3 = 2*Y1 + // Z3 = 2*Y1,新的竖坐标等于纵坐标的两倍 nz = this.y.redAdd(this.y); } else { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html - // #doubling-dbl-2009-l - // 2M + 5S + 13A + // 参考另一个文档链接(hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l)进行计算 + // 2M + 5S + 13A,表示此计算过程中大致涉及的乘法、平方和加法次数 - // A = X1^2 + // A = X1^2,计算横坐标的平方 var a = this.x.redSqr(); - // B = Y1^2 + // B = Y1^2,计算纵坐标的平方 var b = this.y.redSqr(); - // C = B^2 + // C = B^2,计算纵坐标平方的平方 var c = b.redSqr(); - // D = 2 * ((X1 + B)^2 - A - C) + // D = 2 * ((X1 + B)^2 - A - C),按照公式计算D,涉及蒙哥马利域内的加法、平方、减法等运算 var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c); d = d.redIAdd(d); - // E = 3 * A + // E = 3 * A,计算横坐标平方的三倍 var e = a.redAdd(a).redIAdd(a); - // F = E^2 + // F = E^2,计算E的平方 var f = e.redSqr(); - // 8 * C + // 8 * C,通过多次加法计算纵坐标平方的平方的8倍(在蒙哥马利域内) var c8 = c.redIAdd(c); c8 = c8.redIAdd(c8); c8 = c8.redIAdd(c8); - // X3 = F - 2 * D + // X3 = F - 2 * D,按照公式计算新的横坐标,涉及减法运算 nx = f.redISub(d).redISub(d); - // Y3 = E * (D - X3) - 8 * C + // Y3 = E * (D - X3) - 8 * C,按照公式计算新的纵坐标,涉及乘法、减法等运算 ny = e.redMul(d.redISub(nx)).redISub(c8); - // Z3 = 2 * Y1 * Z1 + // Z3 = 2 * Y1 * Z1,新的竖坐标等于纵坐标与竖坐标的乘积的两倍 nz = this.y.redMul(this.z); nz = nz.redIAdd(nz); } + // 使用新计算的坐标nx、ny、nz创建并返回一个新的JPoint对象,表示加倍后的点 return this.curve.jpoint(nx, ny, nz); }; +// JPoint类的实例方法,用于在特定曲线条件(this.curve.threeA为真)下计算点的加倍操作,同样根据点的坐标表示形式有不同计算方式。 JPoint.prototype._threeDbl = function _threeDbl() { var nx; var ny; var nz; - // Z = 1 + // Z = 1,表示点在某种特定情况下(可能是竖坐标为1的简化表示形式)的加倍计算 if (this.zOne) { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html - // #doubling-mdbl-2007-bl - // 1M + 5S + 15A + // 参考特定的文档链接(hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-mdbl-2007-bl)进行计算 + // 1M + 5S + 15A,表示此计算过程中大致涉及的乘法、平方和加法次数 - // XX = X1^2 + // XX = X1^2,计算横坐标的平方 var xx = this.x.redSqr(); - // YY = Y1^2 + // YY = Y1^2,计算纵坐标的平方 var yy = this.y.redSqr(); - // YYYY = YY^2 + // YYYY = YY^2,计算纵坐标平方的平方 var yyyy = yy.redSqr(); - // S = 2 * ((X1 + YY)^2 - XX - YYYY) + // S = 2 * ((X1 + YY)^2 - XX - YYYY),按照公式计算S,涉及蒙哥马利域内的加法、平方、减法等运算 var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); s = s.redIAdd(s); - // M = 3 * XX + a + // M = 3 * XX + a,计算包含曲线参数a的表达式(这里a在特定曲线条件下有特定值,从函数名_threeDbl推测可能与3有关) var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a); - // T = M^2 - 2 * S + // T = M^2 - 2 * S,按照公式计算T,涉及平方和减法运算 var t = m.redSqr().redISub(s).redISub(s); - // X3 = T + // X3 = T,新的横坐标等于T nx = t; - // Y3 = M * (S - T) - 8 * YYYY + // Y3 = M * (S - T) - 8 * YYYY,按照公式计算新的纵坐标,涉及乘法、减法等运算 var yyyy8 = yyyy.redIAdd(yyyy); yyyy8 = yyyy8.redIAdd(yyyy8); yyyy8 = yyyy8.redIAdd(yyyy8); ny = m.redMul(s.redISub(t)).redISub(yyyy8); - // Z3 = 2 * Y1 + // Z3 = 2 * Y1,新的竖坐标等于纵坐标的两倍 nz = this.y.redAdd(this.y); } else { - // hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b - // 3M + 5S + // 参考文档链接(hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b)进行计算 + // 3M + 5S,表示此计算过程中大致涉及的乘法和平方次数 - // delta = Z1^2 + // delta = Z1^2,计算竖坐标的平方 var delta = this.z.redSqr(); - // gamma = Y1^2 + // gamma = Y1^2,计算纵坐标的平方 var gamma = this.y.redSqr(); - // beta = X1 * gamma + // beta = X1 * gamma,计算横坐标与纵坐标平方的乘积 var beta = this.x.redMul(gamma); - // alpha = 3 * (X1 - delta) * (X1 + delta) + // alpha = 3 * (X1 - delta) * (X1 + delta),按照公式计算alpha,涉及蒙哥马利域内的减法、加法、乘法等运算 var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta)); alpha = alpha.redAdd(alpha).redIAdd(alpha); - // X3 = alpha^2 - 8 * beta + // X3 = alpha^2 - 8 * beta,按照公式计算新的横坐标,涉及平方和减法运算 var beta4 = beta.redIAdd(beta); beta4 = beta4.redIAdd(beta4); var beta8 = beta4.redAdd(beta4); nx = alpha.redSqr().redISub(beta8); - // Z3 = (Y1 + Z1)^2 - gamma - delta + // Z3 = (Y1 + Z1)^2 - gamma - delta,按照公式计算新的竖坐标,涉及加法、平方、减法等运算 nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta); - // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2 + // Y3 = alpha * (4 * beta - X3) - 8 * gamma^2,按照公式计算新的纵坐标,涉及乘法、减法、平方等运算 var ggamma8 = gamma.redSqr(); ggamma8 = ggamma8.redIAdd(ggamma8); ggamma8 = ggamma8.redIAdd(ggamma8); @@ -894,9 +1037,108 @@ JPoint.prototype._threeDbl = function _threeDbl() { ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8); } + // 使用新计算的坐标nx、ny、nz创建并返回一个新的JPoint对象,表示加倍后的点 + return this.curve.jpoint(nx, ny, nz); +}; + +// JPoint类的实例方法,用于计算一般情况下点的加倍操作(当曲线不满足this.curve.zeroA和this.curve.threeA特定条件时)。 +JPoint.prototype._dbl = function _dbl() { + var a = this.curve.a; + + // 4M + 6S + 10A,表示此计算过程中大致涉及的乘法、平方和加法次数 + + // 获取当前点的横坐标、纵坐标、竖坐标,并分别赋值给变量,用于后续计算 + var jx = this.x; + var jy = this.y; + var jz = this.z; + // 计算竖坐标的四次方(通过先计算平方再对平方结果计算平方来实现,在蒙哥马利域内进行运算) + var jz4 = jz.redSqr().redSqr(); + + // 计算横坐标的平方和纵坐标的平方,用于后续计算 + var jx2 = jx.redSqr(); + var jy2 = jy.redSqr(); + + // 按照特定的数学公式计算c,涉及横坐标平方的相关运算以及曲线参数a与竖坐标四次方的乘法运算(在蒙哥马利域内) + var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4)); + + // 计算横坐标的两倍(通过多次加法实现,在蒙哥马利域内),并赋值给jxd4 + var jxd4 = jx.redAdd(jx); + jxd4 = jxd4.redIAdd(jxd4); + // 按照公式计算t1,涉及jxd4与jy2的乘法运算(在蒙哥马利域内) + var t1 = jxd4.redMul(jy2); + // 按照公式计算新的横坐标nx,涉及蒙哥马利域内的加法、减法、平方等运算 + var nx = c.redSqr().redISub(t1.redAdd(t1)); + var t2 = t1.redISub(nx); + + // 计算纵坐标平方的四次方(通过多次加法和平方运算实现,在蒙哥马利域内),并赋值给jyd8 + var jyd8 = jy2.redSqr(); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + jyd8 = jyd8.redIAdd(jyd8); + // 按照公式计算新的纵坐标ny,涉及蒙哥马利域内的乘法、减法等运算 + var ny = c.redMul(t2).redISub(jyd8); + // 计算新的竖坐标nz,等于纵坐标的两倍与竖坐标的乘积(在蒙哥马利域内) + var nz = jy.redAdd(jy).redMul(jz); + + // 使用新计算的坐标nx、ny、nz创建并返回一个新的JPoint对象,表示加倍后的点 + return this.curve.jpoint(nx, ny, nz); +}; + +// JPoint类的实例方法,用于计算点的三倍操作(可能是椭圆曲线点运算中的三倍点计算)。 +JPoint.prototype.trpl = function trpl() { + if (!this.curve.zeroA) + // 如果曲线不满足特定条件(this.curve.zeroA为假),通过先加倍再相加的方式计算三倍点(调用this.dbl和add方法) + return this.dbl().add(this); + + // 参考特定的文档链接(hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl)进行计算 + // 5M + 10S +...,表示此计算过程中大致涉及的乘法和平方次数(后面可能还有加法次数等未完整标注,可能在实际应用中需要进一步分析或计算) + + // XX = X1^2,计算横坐标的平方 + var xx = this.x.redSqr(); + // YY = Y1^2,计算纵坐标的平方 + var yy = this.y.redSqr(); + // ZZ = Z1^2,计算竖坐标的平方 + var zz = this.z.redSqr(); + // YYYY = YY^2,计算纵坐标平方的平方 + var yyyy = yy.redSqr(); + // M = 3 * XX + a * ZZ2; a = 0,由于a为0,简化为计算横坐标平方的三倍 + var m = xx.redAdd(xx).redIAdd(xx); + // MM = M^2,计算M的平方 + var mm = m.redSqr(); + // E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM,按照公式计算E,涉及蒙哥马利域内的加法、平方、减法等运算 + var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy); + e = e.redIAdd(e); + e = e.redAdd(e).redIAdd(e); + e = e.redISub(mm); + // EE = E^2,计算E的平方 + var ee = e.redSqr(); + // T = 16*YYYY,通过多次加法计算纵坐标平方的平方的16倍(在蒙哥马利域内) + var t = yyyy.redIAdd(yyyy); + t = t.redIAdd(t); + t = t.redIAdd(t); + t = t.redIAdd(t); + // U = (M + E)^2 - MM - EE - T,按照公式计算U,涉及蒙哥马利域内的加法、平方、减法等运算 + var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t); + // X3 = 4 * (X1 * EE - 4 * YY * U),按照公式计算新的横坐标,涉及蒙哥马利域内的乘法、减法、加法等运算 + var yyu4 = yy.redMul(u); + yyu4 = yyu4.redIAdd(yyu4); + yyu4 = yyu4.redIAdd(yyu4); + var nx = this.x.redMul(ee).redISub(yyu4); + nx = nx.redIAdd(nx); + nx = nx.redIAdd(nx); + // Y3 = 8 * Y1 * (U * (T - U) - E * EE),按照公式计算新的纵坐标,涉及蒙哥马利域内的乘法、减法、加法等运算 + var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee))); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + ny = ny.redIAdd(ny); + // Z3 = (Z1 + E)^2 - ZZ - EE,按照公式计算新的竖坐标,涉及蒙哥马利域内的加法、平方、减法等运算 + var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee); + + // 使用新计算的坐标nx、ny、nz创建并返回一个新的JPoint对象,表示三倍后的点 return this.curve.jpoint(nx, ny, nz); }; +// J JPoint.prototype._dbl = function _dbl() { var a = this.curve.a; -- 2.34.1