|
|
|
|
@ -1,36 +1,52 @@
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
// 引入 `bn.js` 库,用于处理大整数相关操作
|
|
|
|
|
var BN = require('bn.js');
|
|
|
|
|
// 引入自定义的 `utils` 模块,其中包含了一些工具函数
|
|
|
|
|
var utils = require('../utils');
|
|
|
|
|
// 从 `utils` 模块中获取 `getNAF` 函数,用于将整数转换为某种非相邻形式(Non-Adjacent Form,NAF)表示
|
|
|
|
|
var getNAF = utils.getNAF;
|
|
|
|
|
// 从 `utils` 模块中获取 `getJSF` 函数,其功能可能与特定的数学表示形式转换相关(从函数名推测可能是联合稀疏形式相关操作)
|
|
|
|
|
var getJSF = utils.getJSF;
|
|
|
|
|
// 从 `utils` 模块中获取 `assert` 函数,通常用于进行条件判断并在不满足条件时抛出异常
|
|
|
|
|
var assert = utils.assert;
|
|
|
|
|
|
|
|
|
|
// `BaseCurve` 构造函数,用于创建曲线相关的基础对象,不同类型的曲线可能继承自这个基础类来扩展各自的特性
|
|
|
|
|
function BaseCurve(type, conf) {
|
|
|
|
|
// 记录曲线的类型
|
|
|
|
|
this.type = type;
|
|
|
|
|
// 将配置中以十六进制字符串表示的素数 `p` 转换为 `BN` 类型的大整数,并存储起来,这个 `p` 可能与曲线所在的有限域相关
|
|
|
|
|
this.p = new BN(conf.p, 16);
|
|
|
|
|
|
|
|
|
|
// Use Montgomery, when there is no fast reduction for the prime
|
|
|
|
|
this.red = conf.prime ? BN.red(conf.prime) : BN.mont(this.p);
|
|
|
|
|
// 判断配置中是否有 `prime` 属性,如果有则使用 `BN.red` 方法进行某种与素数相关的初始化(可能是蒙哥马利(Montgomery)相关设置),
|
|
|
|
|
// 如果没有则针对当前曲线的素数 `p` 使用 `BN.mont` 方法进行蒙哥马利初始化,`red` 可能用于后续的快速模运算等操作
|
|
|
|
|
this.red = conf.prime? BN.red(conf.prime) : BN.mont(this.p);
|
|
|
|
|
|
|
|
|
|
// Useful for many curves
|
|
|
|
|
// 创建表示数字 0 的蒙哥马利形式,存储在 `this.zero` 中,方便后续在蒙哥马利域下进行运算时使用
|
|
|
|
|
this.zero = new BN(0).toRed(this.red);
|
|
|
|
|
// 创建表示数字 1 的蒙哥马利形式,存储在 `this.one` 中,同样用于蒙哥马利域运算
|
|
|
|
|
this.one = new BN(1).toRed(this.red);
|
|
|
|
|
// 创建表示数字 2 的蒙哥马利形式,存储在 `this.two` 中
|
|
|
|
|
this.two = new BN(2).toRed(this.red);
|
|
|
|
|
|
|
|
|
|
// Curve configuration, optional
|
|
|
|
|
// 如果配置中有 `n` 属性(可能表示曲线的阶数),则将其转换为 `BN` 类型的大整数并存储,否则 `this.n` 为 `undefined`
|
|
|
|
|
this.n = conf.n && new BN(conf.n, 16);
|
|
|
|
|
// 如果配置中有 `g` 属性(可能表示曲线的基点,生成元),则调用 `pointFromJSON` 方法(此方法需在子类中实现,这里是抽象的调用)将其转换为相应的点对象并存储,
|
|
|
|
|
// 同时根据 `gRed` 属性进行相关设置(具体取决于 `pointFromJSON` 方法的实现),如果没有 `g` 属性则 `this.g` 为 `undefined`
|
|
|
|
|
this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed);
|
|
|
|
|
|
|
|
|
|
// Temporary arrays
|
|
|
|
|
// 创建一些临时数组,用于后续计算过程中的临时数据存储,数组长度都初始化为 4,具体用途会在相关计算方法中体现
|
|
|
|
|
this._wnafT1 = new Array(4);
|
|
|
|
|
this._wnafT2 = new Array(4);
|
|
|
|
|
this._wnafT3 = new Array(4);
|
|
|
|
|
this._wnafT4 = new Array(4);
|
|
|
|
|
|
|
|
|
|
this._bitLength = this.n ? this.n.bitLength() : 0;
|
|
|
|
|
// 如果 `this.n` 存在(即曲线阶数已定义),则获取其位数并存储在 `this._bitLength` 中,否则 `this._bitLength` 为 0
|
|
|
|
|
this._bitLength = this.n? this.n.bitLength() : 0;
|
|
|
|
|
|
|
|
|
|
// Generalized Greg Maxwell's trick
|
|
|
|
|
// 进行广义的 Greg Maxwell's trick 相关操作(一种优化技巧,可能与曲线运算性能相关)
|
|
|
|
|
// 计算 `this.p` 除以 `this.n` 的结果,如果不存在 `this.n` 或者除法结果大于 100,则将 `this.redN` 设置为 `null`,
|
|
|
|
|
// 否则设置 `this._maxwellTrick` 为 `true`,并将 `this.n` 转换为蒙哥马利形式存储在 `this.redN` 中
|
|
|
|
|
var adjustCount = this.n && this.p.div(this.n);
|
|
|
|
|
if (!adjustCount || adjustCount.cmpn(100) > 0) {
|
|
|
|
|
this.redN = null;
|
|
|
|
|
@ -39,25 +55,35 @@ function BaseCurve(type, conf) {
|
|
|
|
|
this.redN = this.n.toRed(this.red);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 将 `BaseCurve` 函数暴露出去,方便其他模块使用这个基础曲线类
|
|
|
|
|
module.exports = BaseCurve;
|
|
|
|
|
|
|
|
|
|
// 在 `BaseCurve` 的原型上定义 `point` 方法,此方法在 `BaseCurve` 类中是抽象的,需要在子类中具体实现,
|
|
|
|
|
// 这里直接抛出一个错误表示未实现,调用者应该在子类中重写这个方法来返回相应的曲线点对象
|
|
|
|
|
BaseCurve.prototype.point = function point() {
|
|
|
|
|
throw new Error('Not implemented');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 在 `BaseCurve` 的原型上定义 `validate` 方法,同样是抽象方法,用于验证曲线相关的一些条件是否满足,
|
|
|
|
|
// 在子类中需要重写这个方法来实现具体的验证逻辑,这里直接抛出错误表示未实现
|
|
|
|
|
BaseCurve.prototype.validate = function validate() {
|
|
|
|
|
throw new Error('Not implemented');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// `_fixedNafMul` 方法,用于基于固定宽度的非相邻形式(NAF)进行乘法相关运算(可能是点乘之类的操作,具体取决于上下文和 `p`、`k` 的含义)
|
|
|
|
|
BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) {
|
|
|
|
|
// 断言 `p` 对象有 `precomputed` 属性(可能表示 `p` 相关的预计算数据已准备好,具体取决于对象结构和应用场景),如果不满足则抛出异常
|
|
|
|
|
assert(p.precomputed);
|
|
|
|
|
// 获取 `p` 对象的 `_getDoubles` 方法返回的结果,这个方法应该返回与双倍相关的数据(比如预计算的双倍点等信息,具体取决于实现)
|
|
|
|
|
var doubles = p._getDoubles();
|
|
|
|
|
|
|
|
|
|
// 使用 `getNAF` 函数将整数 `k` 转换为宽度为 1 的非相邻形式表示,传入曲线的位数 `this._bitLength` 用于控制相关计算范围等
|
|
|
|
|
var naf = getNAF(k, 1, this._bitLength);
|
|
|
|
|
var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1);
|
|
|
|
|
// 计算一个与双倍相关的参数 `I`,具体计算逻辑根据给定的表达式,可能与双倍点的步长等信息有关,用于后续的计算转换
|
|
|
|
|
var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0? 2 : 1);
|
|
|
|
|
I /= 3;
|
|
|
|
|
|
|
|
|
|
// Translate into more windowed form
|
|
|
|
|
// 将 `naf` 表示转换为更适合窗口形式的表示形式,存储在 `repr` 数组中,具体转换逻辑通过循环遍历 `naf` 并按一定规则合并位来实现
|
|
|
|
|
var repr = [];
|
|
|
|
|
var j;
|
|
|
|
|
var nafW;
|
|
|
|
|
@ -68,89 +94,111 @@ BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) {
|
|
|
|
|
repr.push(nafW);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建两个曲线点对象 `a` 和 `b`,初始化为 `null`(这里的 `jpoint` 方法应该是创建特定类型曲线点的方法,具体功能取决于实现)
|
|
|
|
|
var a = this.jpoint(null, null, null);
|
|
|
|
|
var b = this.jpoint(null, null, null);
|
|
|
|
|
// 外层循环,根据 `I` 的值进行迭代,可能与计算次数等相关
|
|
|
|
|
for (var i = I; i > 0; i--) {
|
|
|
|
|
// 内层循环,遍历 `repr` 数组中的每个元素(即窗口化后的 `naf` 表示形式)
|
|
|
|
|
for (j = 0; j < repr.length; j++) {
|
|
|
|
|
nafW = repr[j];
|
|
|
|
|
// 如果当前元素等于 `i`,则调用 `b` 的 `mixedAdd` 方法(可能是混合加法操作,具体取决于曲线点对象的实现)将对应的双倍点加到 `b` 上
|
|
|
|
|
if (nafW === i)
|
|
|
|
|
b = b.mixedAdd(doubles.points[j]);
|
|
|
|
|
// 如果当前元素等于 `-i`,则调用 `b` 的 `mixedAdd` 方法将对应的双倍点的相反数加到 `b` 上
|
|
|
|
|
else if (nafW === -i)
|
|
|
|
|
b = b.mixedAdd(doubles.points[j].neg());
|
|
|
|
|
}
|
|
|
|
|
// 将 `b` 的结果累加到 `a` 上,通过调用 `a` 的 `add` 方法(点加法操作)
|
|
|
|
|
a = a.add(b);
|
|
|
|
|
}
|
|
|
|
|
// 根据 `p` 的类型,如果是 `affine` 类型(仿射坐标类型,一种表示曲线点的方式),则调用 `toP` 方法(可能是转换为某种特定格式的点表示)将 `a` 转换后返回,否则直接返回 `a`
|
|
|
|
|
return a.toP();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// `_wnafMul` 方法,用于基于窗口宽度为 4 的非相邻形式(w-NAF)进行乘法相关运算(同样可能是点乘操作等)
|
|
|
|
|
BaseCurve.prototype._wnafMul = function _wnafMul(p, k) {
|
|
|
|
|
// 设置窗口宽度为 4,这个宽度会影响后续非相邻形式的计算和相关预计算等操作
|
|
|
|
|
var w = 4;
|
|
|
|
|
|
|
|
|
|
// Precompute window
|
|
|
|
|
// 调用 `p` 对象的 `_getNAFPoints` 方法(应该是获取与非相邻形式相关的预计算点信息),传入窗口宽度 `w`,获取预计算的点相关信息并存储在 `nafPoints` 中,
|
|
|
|
|
// 同时更新 `w` 为实际获取到的窗口宽度(可能在 `_getNAFPoints` 方法中根据实际情况进行了调整),获取预计算的点数组存储在 `wnd` 中
|
|
|
|
|
var nafPoints = p._getNAFPoints(w);
|
|
|
|
|
w = nafPoints.wnd;
|
|
|
|
|
var wnd = nafPoints.points;
|
|
|
|
|
|
|
|
|
|
// Get NAF form
|
|
|
|
|
// 使用 `getNAF` 函数将整数 `k` 转换为宽度为 `w` 的非相邻形式表示,传入曲线的位数 `this._bitLength` 用于控制相关计算范围等
|
|
|
|
|
var naf = getNAF(k, w, this._bitLength);
|
|
|
|
|
|
|
|
|
|
// Add `this`*(N+1) for every w-NAF index
|
|
|
|
|
// 创建一个曲线点对象 `acc`,初始化为 `null`(同样通过 `jpoint` 方法创建,具体功能取决于实现),用于累加计算结果
|
|
|
|
|
var acc = this.jpoint(null, null, null);
|
|
|
|
|
// 从 `naf` 数组的末尾开始向前遍历(反向遍历,可能与计算顺序相关)
|
|
|
|
|
for (var i = naf.length - 1; i >= 0; i--) {
|
|
|
|
|
// Count zeroes
|
|
|
|
|
// 统计连续的 0 的个数,通过循环递减 `i` 直到遇到非 0 值或者 `i` 小于 0
|
|
|
|
|
for (var l = 0; i >= 0 && naf[i] === 0; i--)
|
|
|
|
|
l++;
|
|
|
|
|
if (i >= 0)
|
|
|
|
|
l++;
|
|
|
|
|
// 根据连续 0 的个数对 `acc` 进行双倍操作(`dblp` 方法可能是点的双倍运算,具体取决于曲线点对象的实现)
|
|
|
|
|
acc = acc.dblp(l);
|
|
|
|
|
|
|
|
|
|
if (i < 0)
|
|
|
|
|
break;
|
|
|
|
|
var z = naf[i];
|
|
|
|
|
assert(z !== 0);
|
|
|
|
|
// 断言 `z` 不为 0,如果为 0 则抛出异常(这里可能是基于算法逻辑要求非相邻形式表示中不应出现连续多个 0 的情况等)
|
|
|
|
|
assert(z!== 0);
|
|
|
|
|
if (p.type === 'affine') {
|
|
|
|
|
// J +- P
|
|
|
|
|
// 如果 `p` 的类型是 `affine`(仿射坐标类型),根据 `z` 的正负情况,调用 `acc` 的 `mixedAdd` 方法将对应的预计算点或其相反数加到 `acc` 上(`J +- P` 表示的可能是某种点加法逻辑)
|
|
|
|
|
if (z > 0)
|
|
|
|
|
acc = acc.mixedAdd(wnd[(z - 1) >> 1]);
|
|
|
|
|
else
|
|
|
|
|
acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg());
|
|
|
|
|
} else {
|
|
|
|
|
// J +- J
|
|
|
|
|
// 如果 `p` 不是 `affine` 类型,同样根据 `z` 的正负情况,调用 `acc` 的 `add` 方法将对应的预计算点或其相反数加到 `acc` 上(`J +- J` 表示的可能是另一种点加法逻辑)
|
|
|
|
|
if (z > 0)
|
|
|
|
|
acc = acc.add(wnd[(z - 1) >> 1]);
|
|
|
|
|
else
|
|
|
|
|
acc = acc.add(wnd[(-z - 1) >> 1].neg());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return p.type === 'affine' ? acc.toP() : acc;
|
|
|
|
|
// 根据 `p` 的类型,如果是 `affine` 类型则调用 `toP` 方法将 `acc` 转换后返回,否则直接返回 `acc`
|
|
|
|
|
return p.type === 'affine'? acc.toP() : acc;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// `_wnafMulAdd` 方法,用于基于窗口非相邻形式(w-NAF)进行乘法和加法相关的混合运算,传入了多个参数用于控制计算过程
|
|
|
|
|
BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW,
|
|
|
|
|
points,
|
|
|
|
|
coeffs,
|
|
|
|
|
len,
|
|
|
|
|
jacobianResult) {
|
|
|
|
|
points,
|
|
|
|
|
coeffs,
|
|
|
|
|
len,
|
|
|
|
|
jacobianResult) {
|
|
|
|
|
// 获取临时数组 `this._wnafT1`,用于存储窗口宽度相关信息(从变量名推测),可能在后续计算中用于记录每个点对应的窗口宽度等
|
|
|
|
|
var wndWidth = this._wnafT1;
|
|
|
|
|
// 获取临时数组 `this._wnafT2`,用于存储预计算的点相关信息(同样从变量名推测),可能是每个点对应的窗口非相邻形式的预计算点数组等
|
|
|
|
|
var wnd = this._wnafT2;
|
|
|
|
|
// 获取临时数组 `this._wnafT3`,用于存储非相邻形式(NAF)表示的数据(推测),可能是每个系数对应的非相邻形式表示等
|
|
|
|
|
var naf = this._wnafT3;
|
|
|
|
|
|
|
|
|
|
// Fill all arrays
|
|
|
|
|
// 初始化一个变量 `max` 为 0,用于记录后续计算中出现的最大长度(可能是 NAF 表示的长度等)
|
|
|
|
|
var max = 0;
|
|
|
|
|
var i;
|
|
|
|
|
var j;
|
|
|
|
|
var p;
|
|
|
|
|
// 循环遍历传入的点数组 `points`,填充相关的临时数组 `wndWidth` 和 `wnd`
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
p = points[i];
|
|
|
|
|
// 调用每个点 `p` 的 `_getNAFPoints` 方法(获取与非相邻形式相关的预计算点信息),传入默认窗口宽度 `defW`,获取并存储窗口宽度和预计算点信息到相应的临时数组中
|
|
|
|
|
var nafPoints = p._getNAFPoints(defW);
|
|
|
|
|
wndWidth[i] = nafPoints.wnd;
|
|
|
|
|
wnd[i] = nafPoints.points;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Comb small window NAFs
|
|
|
|
|
// 从后往前每隔 2 个元素进行循环(可能是对相邻的点和系数进行组合操作,具体取决于算法逻辑),用于组合小窗口的非相邻形式(NAF)表示
|
|
|
|
|
for (i = len - 1; i >= 1; i -= 2) {
|
|
|
|
|
var a = i - 1;
|
|
|
|
|
var b = i;
|
|
|
|
|
if (wndWidth[a] !== 1 || wndWidth[b] !== 1) {
|
|
|
|
|
// 如果两个相邻点对应的窗口宽度不为 1,则分别调用 `getNAF` 函数将对应的系数转换为非相邻形式表示,
|
|
|
|
|
// 并更新 `max` 为当前两个非相邻形式表示长度中的最大值,然后继续下一轮循环
|
|
|
|
|
if (wndWidth[a]!== 1 || wndWidth[b]!== 1) {
|
|
|
|
|
naf[a] = getNAF(coeffs[a], wndWidth[a], this._bitLength);
|
|
|
|
|
naf[b] = getNAF(coeffs[b], wndWidth[b], this._bitLength);
|
|
|
|
|
max = Math.max(naf[a].length, max);
|
|
|
|
|
@ -158,6 +206,8 @@ BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW,
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建一个包含 4 个元素的数组 `comb`,用于存储一些点的组合情况,初始值部分设置为 `points[a]` 和 `null`,
|
|
|
|
|
// 具体含义和后续用途取决于下面的条件判断和赋值逻辑,这里可能是在尝试通过点的组合来优化计算等
|
|
|
|
|
var comb = [
|
|
|
|
|
points[a], /* 1 */
|
|
|
|
|
null, /* 3 */
|
|
|
|
|
@ -165,18 +215,9 @@ BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW,
|
|
|
|
|
points[b], /* 7 */
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Try to avoid Projective points, if possible
|
|
|
|
|
if (points[a].y.cmp(points[b].y) === 0) {
|
|
|
|
|
comb[1] = points[a].add(points[b]);
|
|
|
|
|
comb[2] = points[a].toJ().mixedAdd(points[b].neg());
|
|
|
|
|
} else if (points[a].y.cmp(points[b].y.redNeg()) === 0) {
|
|
|
|
|
comb[1] = points[a].toJ().mixedAdd(points[b]);
|
|
|
|
|
comb[2] = points[a].add(points[b].neg());
|
|
|
|
|
} else {
|
|
|
|
|
comb[1] = points[a].toJ().mixedAdd(points[b]);
|
|
|
|
|
comb[2] = points[a].toJ().mixedAdd(points[b].neg());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 尝试避免使用射影坐标(Projective points,一种曲线点的表示方式),根据两个点的 `y` 坐标的比较情况进行不同的点组合操作,
|
|
|
|
|
// 如果两个点的 `y` 坐标相等,则进行特定的点加法操作并赋值给 `comb` 数组中的相应位置,
|
|
|
|
|
// 如果两个点的 `y` 坐标互为相反数(通过 `redNeg` 方法判断,可能是蒙哥马利域下的取相反数操作),则进行另
|
|
|
|
|
var index = [
|
|
|
|
|
-3, /* -1 -1 */
|
|
|
|
|
-1, /* -1 0 */
|
|
|
|
|
@ -189,193 +230,229 @@ BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW,
|
|
|
|
|
3, /* 1 1 */
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
var jsf = getJSF(coeffs[a], coeffs[b]);
|
|
|
|
|
max = Math.max(jsf[0].length, max);
|
|
|
|
|
naf[a] = new Array(max);
|
|
|
|
|
naf[b] = new Array(max);
|
|
|
|
|
// 从给定的系数中获取 JSF(Jacobian Scalar Form)
|
|
|
|
|
var jsf = getJSF(coeffs[a], coeffs[b]); // 获取系数 a 和 b 的 Jacobian 标量形式
|
|
|
|
|
max = Math.max(jsf[0].length, max); // 更新最大长度
|
|
|
|
|
naf[a] = new Array(max); // 为 naf 数组的 a 分配最大长度
|
|
|
|
|
naf[b] = new Array(max); // 为 naf 数组的 b 分配最大长度
|
|
|
|
|
|
|
|
|
|
// 遍历最大长度
|
|
|
|
|
for (j = 0; j < max; j++) {
|
|
|
|
|
var ja = jsf[0][j] | 0;
|
|
|
|
|
var jb = jsf[1][j] | 0;
|
|
|
|
|
var ja = jsf[0][j] | 0; // 获取 jsf 的第一个部分的值并转为整数
|
|
|
|
|
var jb = jsf[1][j] | 0; // 获取 jsf 的第二个部分的值并转为整数
|
|
|
|
|
|
|
|
|
|
naf[a][j] = index[(ja + 1) * 3 + (jb + 1)];
|
|
|
|
|
naf[b][j] = 0;
|
|
|
|
|
wnd[a] = comb;
|
|
|
|
|
// 根据 ja 和 jb 的值更新 naf 数组
|
|
|
|
|
naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; // 使用 index 数组计算 naf[a][j]
|
|
|
|
|
naf[b][j] = 0; // 将 naf[b][j] 设置为 0
|
|
|
|
|
wnd[a] = comb; // 将 wnd[a] 设置为 comb(组合预计算值)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var acc = this.jpoint(null, null, null);
|
|
|
|
|
var tmp = this._wnafT4;
|
|
|
|
|
for (i = max; i >= 0; i--) {
|
|
|
|
|
var k = 0;
|
|
|
|
|
// 初始化一个新的 Jacobian 点
|
|
|
|
|
var acc = this.jpoint(null, null, null); // 创建一个新的 Jacobian 点
|
|
|
|
|
var tmp = this._wnafT4; // 获取临时数组,用于存储 WNAF(宽度非负数表示法)值
|
|
|
|
|
|
|
|
|
|
// 从最大长度开始逆向迭代
|
|
|
|
|
for (i = max; i >= 0; i--) {
|
|
|
|
|
var k = 0; // 初始化 k,用于记录零的数量
|
|
|
|
|
|
|
|
|
|
// 检查当前索引 i 的 WNAF 值
|
|
|
|
|
while (i >= 0) {
|
|
|
|
|
var zero = true; // 假设当前为零
|
|
|
|
|
for (j = 0; j < len; j++) {
|
|
|
|
|
tmp[j] = naf[j][i] | 0; // 将 naf[j][i] 的值存入临时数组并转为整数
|
|
|
|
|
if (tmp[j] !== 0) // 如果值不为零
|
|
|
|
|
zero = false; // 标记为非零
|
|
|
|
|
}
|
|
|
|
|
if (!zero) // 如果有非零值
|
|
|
|
|
break; // 退出循环
|
|
|
|
|
k++; // 计数零的数量
|
|
|
|
|
i--; // 减少 i 值
|
|
|
|
|
}
|
|
|
|
|
if (i >= 0) // 如果 i 仍然有效
|
|
|
|
|
k++; // 增加 k
|
|
|
|
|
|
|
|
|
|
acc = acc.dblp(k); // 对累加器进行 k 次双倍操作
|
|
|
|
|
if (i < 0) // 如果 i 小于 0,退出循环
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
while (i >= 0) {
|
|
|
|
|
var zero = true;
|
|
|
|
|
// 遍历所有的 len
|
|
|
|
|
for (j = 0; j < len; j++) {
|
|
|
|
|
tmp[j] = naf[j][i] | 0;
|
|
|
|
|
if (tmp[j] !== 0)
|
|
|
|
|
zero = false;
|
|
|
|
|
var z = tmp[j]; // 获取临时数组的当前值
|
|
|
|
|
p; // 声明变量 p
|
|
|
|
|
if (z === 0) // 如果 z 为零
|
|
|
|
|
continue; // 跳过
|
|
|
|
|
else if (z > 0) // 如果 z 为正
|
|
|
|
|
p = wnd[j][(z - 1) >> 1]; // 获取正值的预计算点
|
|
|
|
|
else if (z < 0) // 如果 z 为负
|
|
|
|
|
p = wnd[j][(-z - 1) >> 1].neg(); // 获取负值的预计算点并取反
|
|
|
|
|
|
|
|
|
|
// 根据 p 的类型选择不同的加法方式
|
|
|
|
|
if (p.type === 'affine') // 如果 p 是仿射点
|
|
|
|
|
acc = acc.mixedAdd(p); // 使用混合加法
|
|
|
|
|
else // 如果 p 是 Jacobian 点
|
|
|
|
|
acc = acc.add(p); // 使用普通加法
|
|
|
|
|
}
|
|
|
|
|
if (!zero)
|
|
|
|
|
break;
|
|
|
|
|
k++;
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
if (i >= 0)
|
|
|
|
|
k++;
|
|
|
|
|
acc = acc.dblp(k);
|
|
|
|
|
if (i < 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < len; j++) {
|
|
|
|
|
var z = tmp[j];
|
|
|
|
|
p;
|
|
|
|
|
if (z === 0)
|
|
|
|
|
continue;
|
|
|
|
|
else if (z > 0)
|
|
|
|
|
p = wnd[j][(z - 1) >> 1];
|
|
|
|
|
else if (z < 0)
|
|
|
|
|
p = wnd[j][(-z - 1) >> 1].neg();
|
|
|
|
|
|
|
|
|
|
if (p.type === 'affine')
|
|
|
|
|
acc = acc.mixedAdd(p);
|
|
|
|
|
else
|
|
|
|
|
acc = acc.add(p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Zeroify references
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
wnd[i] = null;
|
|
|
|
|
|
|
|
|
|
if (jacobianResult)
|
|
|
|
|
return acc;
|
|
|
|
|
else
|
|
|
|
|
return acc.toP();
|
|
|
|
|
};
|
|
|
|
|
// 清理引用,将 wnd 数组的每个元素设置为 null
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
wnd[i] = null; // 清除 wnd 数组中的引用
|
|
|
|
|
|
|
|
|
|
function BasePoint(curve, type) {
|
|
|
|
|
this.curve = curve;
|
|
|
|
|
this.type = type;
|
|
|
|
|
this.precomputed = null;
|
|
|
|
|
}
|
|
|
|
|
BaseCurve.BasePoint = BasePoint;
|
|
|
|
|
// 根据 jacobianResult 的值决定返回值
|
|
|
|
|
if (jacobianResult)
|
|
|
|
|
return acc; // 如果需要 Jacobian 结果,则返回 acc
|
|
|
|
|
else
|
|
|
|
|
return acc.toP(); // 否则返回转换为仿射坐标的 acc
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype.eq = function eq(/*other*/) {
|
|
|
|
|
throw new Error('Not implemented');
|
|
|
|
|
};
|
|
|
|
|
// 定义 BasePoint 构造函数
|
|
|
|
|
function BasePoint(curve, type) {
|
|
|
|
|
this.curve = curve; // 保存曲线对象
|
|
|
|
|
this.type = type; // 保存类型
|
|
|
|
|
this.precomputed = null; // 初始化预计算值为 null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype.validate = function validate() {
|
|
|
|
|
return this.curve.validate(this);
|
|
|
|
|
};
|
|
|
|
|
// 将 BasePoint 赋值给 BaseCurve 的 BasePoint 属性
|
|
|
|
|
BaseCurve.BasePoint = BasePoint;
|
|
|
|
|
|
|
|
|
|
BaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) {
|
|
|
|
|
bytes = utils.toArray(bytes, enc);
|
|
|
|
|
// 定义点的相等性比较方法,当前未实现
|
|
|
|
|
BasePoint.prototype.eq = function eq(/*other*/) {
|
|
|
|
|
throw new Error('Not implemented'); // 抛出未实现的错误
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var len = this.p.byteLength();
|
|
|
|
|
// 验证当前点是否在曲线上
|
|
|
|
|
BasePoint.prototype.validate = function validate() {
|
|
|
|
|
return this.curve.validate(this); // 调用曲线的验证方法
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// uncompressed, hybrid-odd, hybrid-even
|
|
|
|
|
if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) &&
|
|
|
|
|
bytes.length - 1 === 2 * len) {
|
|
|
|
|
if (bytes[0] === 0x06)
|
|
|
|
|
assert(bytes[bytes.length - 1] % 2 === 0);
|
|
|
|
|
else if (bytes[0] === 0x07)
|
|
|
|
|
assert(bytes[bytes.length - 1] % 2 === 1);
|
|
|
|
|
// 解码点的字节表示
|
|
|
|
|
BaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) {
|
|
|
|
|
// 将字节转换为数组
|
|
|
|
|
bytes = utils.toArray(bytes, enc);
|
|
|
|
|
|
|
|
|
|
var len = this.p.byteLength(); // 获取曲线的参数长度
|
|
|
|
|
|
|
|
|
|
// 处理未压缩、混合奇偶形式的点
|
|
|
|
|
if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) &&
|
|
|
|
|
bytes.length - 1 === 2 * len) {
|
|
|
|
|
if (bytes[0] === 0x06)
|
|
|
|
|
assert(bytes[bytes.length - 1] % 2 === 0); // 校验最后一个字节为偶数
|
|
|
|
|
else if (bytes[0] === 0x07)
|
|
|
|
|
assert(bytes[bytes.length - 1] % 2 === 1); // 校验最后一个字节为奇数
|
|
|
|
|
|
|
|
|
|
// 创建点对象并返回
|
|
|
|
|
var res = this.point(bytes.slice(1, 1 + len),
|
|
|
|
|
bytes.slice(1 + len, 1 + 2 * len));
|
|
|
|
|
|
|
|
|
|
return res; // 返回解码后的点
|
|
|
|
|
} else if ((bytes[0] === 0x02 || bytes[0] === 0x03) &&
|
|
|
|
|
bytes.length - 1 === len) {
|
|
|
|
|
// 处理压缩形式的点
|
|
|
|
|
return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03);
|
|
|
|
|
}
|
|
|
|
|
throw new Error('Unknown point format'); // 抛出未知格式的错误
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var res = this.point(bytes.slice(1, 1 + len),
|
|
|
|
|
bytes.slice(1 + len, 1 + 2 * len));
|
|
|
|
|
// 压缩编码点
|
|
|
|
|
BasePoint.prototype.encodeCompressed = function encodeCompressed(enc) {
|
|
|
|
|
return this.encode(enc, true); // 调用 encode 方法,设置为压缩格式
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
} else if ((bytes[0] === 0x02 || bytes[0] === 0x03) &&
|
|
|
|
|
bytes.length - 1 === len) {
|
|
|
|
|
return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03);
|
|
|
|
|
}
|
|
|
|
|
throw new Error('Unknown point format');
|
|
|
|
|
};
|
|
|
|
|
// 编码点为字节数组
|
|
|
|
|
BasePoint.prototype._encode = function _encode(compact) {
|
|
|
|
|
var len = this.curve.p.byteLength(); // 获取曲线参数长度
|
|
|
|
|
var x = this.getX().toArray('be', len); // 获取 x 坐标并转换为字节数组
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype.encodeCompressed = function encodeCompressed(enc) {
|
|
|
|
|
return this.encode(enc, true);
|
|
|
|
|
};
|
|
|
|
|
if (compact)
|
|
|
|
|
return [ this.getY().isEven() ? 0x02 : 0x03 ].concat(x); // 返回压缩格式
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype._encode = function _encode(compact) {
|
|
|
|
|
var len = this.curve.p.byteLength();
|
|
|
|
|
var x = this.getX().toArray('be', len);
|
|
|
|
|
return [ 0x04 ].concat(x, this.getY().toArray('be', len)); // 返回未压缩格式
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (compact)
|
|
|
|
|
return [ this.getY().isEven() ? 0x02 : 0x03 ].concat(x);
|
|
|
|
|
// 编码点为指定格式
|
|
|
|
|
BasePoint.prototype.encode = function encode(enc, compact) {
|
|
|
|
|
return utils.encode(this._encode(compact), enc); // 调用 utils.encode 进行编码
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return [ 0x04 ].concat(x, this.getY().toArray('be', len));
|
|
|
|
|
};
|
|
|
|
|
// 预计算点的倍数
|
|
|
|
|
BasePoint.prototype.precompute = function precompute(power) {
|
|
|
|
|
if (this.precomputed)
|
|
|
|
|
return this; // 如果已经预计算,直接返回
|
|
|
|
|
|
|
|
|
|
var precomputed = {
|
|
|
|
|
doubles: null, // 存储倍点
|
|
|
|
|
naf: null, // 存储 NAF 点
|
|
|
|
|
beta: null, // 存储 beta
|
|
|
|
|
};
|
|
|
|
|
precomputed.naf = this._getNAFPoints(8); // 获取 NAF 点
|
|
|
|
|
precomputed.doubles = this._getDoubles(4, power); // 获取倍点
|
|
|
|
|
precomputed.beta = this._getBeta(); // 获取 beta
|
|
|
|
|
this.precomputed = precomputed; // 存储预计算结果
|
|
|
|
|
|
|
|
|
|
return this; // 返回当前点
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype.encode = function encode(enc, compact) {
|
|
|
|
|
return utils.encode(this._encode(compact), enc);
|
|
|
|
|
};
|
|
|
|
|
// 检查是否有足够的倍点
|
|
|
|
|
BasePoint.prototype._hasDoubles = function _hasDoubles(k) {
|
|
|
|
|
if (!this.precomputed)
|
|
|
|
|
return false; // 如果没有预计算,返回 false
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype.precompute = function precompute(power) {
|
|
|
|
|
if (this.precomputed)
|
|
|
|
|
return this;
|
|
|
|
|
var doubles = this.precomputed.doubles; // 获取倍点
|
|
|
|
|
if (!doubles)
|
|
|
|
|
return false; // 如果没有倍点,返回 false
|
|
|
|
|
|
|
|
|
|
var precomputed = {
|
|
|
|
|
doubles: null,
|
|
|
|
|
naf: null,
|
|
|
|
|
beta: null,
|
|
|
|
|
// 检查倍点数量是否足够
|
|
|
|
|
return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step);
|
|
|
|
|
};
|
|
|
|
|
precomputed.naf = this._getNAFPoints(8);
|
|
|
|
|
precomputed.doubles = this._getDoubles(4, power);
|
|
|
|
|
precomputed.beta = this._getBeta();
|
|
|
|
|
this.precomputed = precomputed;
|
|
|
|
|
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
// 获取倍点的函数
|
|
|
|
|
BasePoint.prototype._getDoubles = function _getDoubles(step, power) {
|
|
|
|
|
if (this.precomputed && this.precomputed.doubles)
|
|
|
|
|
return this.precomputed.doubles; // 如果已经预计算,直接返回
|
|
|
|
|
|
|
|
|
|
var doubles = [ this ]; // 初始化倍点数组
|
|
|
|
|
var acc = this; // 记录当前点
|
|
|
|
|
for (var i = 0; i < power; i += step) {
|
|
|
|
|
for (var j = 0; j < step; j++)
|
|
|
|
|
acc = acc.dbl(); // 计算倍点
|
|
|
|
|
doubles.push(acc); // 添加倍点到数组
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
step: step,
|
|
|
|
|
points: doubles, // 返回倍点和步长
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype._hasDoubles = function _hasDoubles(k) {
|
|
|
|
|
if (!this.precomputed)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
var doubles = this.precomputed.doubles;
|
|
|
|
|
if (!doubles)
|
|
|
|
|
return false;
|
|
|
|
|
// 获取 NAF 点的函数
|
|
|
|
|
BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) {
|
|
|
|
|
// 如果已经预计算过 NAF 点,直接返回
|
|
|
|
|
if (this.precomputed && this.precomputed.naf)
|
|
|
|
|
return this.precomputed.naf;
|
|
|
|
|
|
|
|
|
|
return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step);
|
|
|
|
|
};
|
|
|
|
|
var res = [ this ]; // 初始化结果数组,包含当前点
|
|
|
|
|
var max = (1 << wnd) - 1; // 计算最大值,wnd 为窗口大小
|
|
|
|
|
var dbl = max === 1 ? null : this.dbl(); // 如果最大值为 1,则不需要计算倍点
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype._getDoubles = function _getDoubles(step, power) {
|
|
|
|
|
if (this.precomputed && this.precomputed.doubles)
|
|
|
|
|
return this.precomputed.doubles;
|
|
|
|
|
// 生成 NAF 点
|
|
|
|
|
for (var i = 1; i < max; i++)
|
|
|
|
|
res[i] = res[i - 1].add(dbl); // 当前点加上倍点,得到下一个点
|
|
|
|
|
|
|
|
|
|
var doubles = [ this ];
|
|
|
|
|
var acc = this;
|
|
|
|
|
for (var i = 0; i < power; i += step) {
|
|
|
|
|
for (var j = 0; j < step; j++)
|
|
|
|
|
acc = acc.dbl();
|
|
|
|
|
doubles.push(acc);
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
step: step,
|
|
|
|
|
points: doubles,
|
|
|
|
|
return {
|
|
|
|
|
wnd: wnd, // 返回窗口大小
|
|
|
|
|
points: res, // 返回 NAF 点数组
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) {
|
|
|
|
|
if (this.precomputed && this.precomputed.naf)
|
|
|
|
|
return this.precomputed.naf;
|
|
|
|
|
|
|
|
|
|
var res = [ this ];
|
|
|
|
|
var max = (1 << wnd) - 1;
|
|
|
|
|
var dbl = max === 1 ? null : this.dbl();
|
|
|
|
|
for (var i = 1; i < max; i++)
|
|
|
|
|
res[i] = res[i - 1].add(dbl);
|
|
|
|
|
return {
|
|
|
|
|
wnd: wnd,
|
|
|
|
|
points: res,
|
|
|
|
|
// 获取 beta 值的函数,当前未实现
|
|
|
|
|
BasePoint.prototype._getBeta = function _getBeta() {
|
|
|
|
|
return null; // 返回 null,表示未实现
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype._getBeta = function _getBeta() {
|
|
|
|
|
return null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
BasePoint.prototype.dblp = function dblp(k) {
|
|
|
|
|
var r = this;
|
|
|
|
|
for (var i = 0; i < k; i++)
|
|
|
|
|
r = r.dbl();
|
|
|
|
|
return r;
|
|
|
|
|
};
|
|
|
|
|
// 点的倍增操作,倍增 k 次
|
|
|
|
|
BasePoint.prototype.dblp = function dblp(k) {
|
|
|
|
|
var r = this; // 初始化结果为当前点
|
|
|
|
|
for (var i = 0; i < k; i++)
|
|
|
|
|
r = r.dbl(); // 重复倍增操作
|
|
|
|
|
return r; // 返回 k 倍的点
|
|
|
|
|
};
|
|
|
|
|
|