怀陶宁 发表于 10 小时前

secp256k1算法详解三(点操作关键理论及源码分析)

1 基础概念

1.1 Short Weierstrass Curve

椭圆曲线(Elliptic Curve,EC)是密码学中非常重要的代数结构,在几何上,椭圆曲线是由三次方程描述的一些曲线。不同的公式给出了不同曲线形式,对于维尔斯特拉斯形式的椭圆曲线,其定义在域K上的椭圆曲线E由下述方程定义:

例如椭圆曲线y2 + xy + y = x3 - x + 1图形如下所示:

详细内容可以参考:张焕国著《椭圆曲线密码学导论》。由于一般形式的维尔斯特拉斯方程系数太多不利于分析,一般多基于短维尔斯特拉斯曲线(当域K的特征≠2,3时,一般形式维尔斯特拉斯可以简化为短维尔斯特拉斯)进行研究,它是有以下方程描述的椭圆曲线:
y2 = x3 + ax + b
参数a,b满足条件:4a3+27b2≠0,限定条件是为了保证曲线不包含奇点(singularities某些特定方面不再表现良好的点,例如缺乏可微性或可分析性)。在椭圆曲线密码学中x,y以及参数a,b都属于有限域Fp,如对于secp256k1曲线,参数a=0,b=7,即公式进一步简化为y2 = x3 + 7。
1.2 点加及倍点

在椭圆曲线上定义了两个点的加法运算,两个点P和点Q之和点为R,则R是过P,Q点直线与椭圆曲线交点关于x轴的对称点,这里P和Q的横坐标不同时,当P和Q重合时(横纵坐标都相同),则R是过P点切线与椭圆曲线交点关于x轴的对称点,如下图所示:

为了理论的完整性,还引入无穷远点的概念,这时对应P和Q横坐标相同纵坐标不同,则它们和点即为无穷远点(此时P和Q互为对方逆元),这里不再详细介绍相关内容,请自行查阅有关资料。
1.3 仿射坐标(Affine Coordinates)

维尔斯特拉斯形式曲线上点的坐标就是椭圆曲线点的仿射坐标(x, y),接下来基于仿射坐标分析下点加及倍点运算。对于椭圆曲线上两个点P(x1, y1),Q(x2, y2),令R(x3, y3) = P + Q,当x1 ≠ x2时,过P,Q点直线坐标为y=λx + m,代入到椭圆曲线方程得
x3 - λ2x2 + (a - 2λm)x + b - m2 = 0
设直线与椭圆曲线交点为R'(x', y'),则可知x1,x2,x'是以上一元三次方程的根,由韦达定理可知:-x1 - x2 - x' = -λ2,则有:

其中λ是直线斜率。因为R是R'关于x轴对称点,所以R坐标为(λ2 - x1 - x2, (2x1 + x2 - λ2)λ -y1),带入λ有以下计算公式:

当P和Q重合时(且y ≠ 0),对椭圆曲线公式两边关于x求导得斜率:

进而得倍点公式:

1.4 射影坐标(Projective Coordinates)

在数学和密码学领域,射影坐标(Projective Coordinates) 是一种通过引入额外维度来避免除法运算的坐标表示方法,在传统的仿射坐标(Affine Coordinates) 中,平面上的点用二维坐标(x, y)表示,对应笛卡尔坐标系中的位置。但仿射坐标在处理涉及除法的运算(如椭圆曲线的点加法、点加倍)时,会引入计算成本较高的逆元操作(有限域中的除法等价于乘以逆元)。射影坐标通过引入一个额外的非零参数Z,将仿射坐标(x, y)扩展为三维坐标(X, Y, Z),其中Z ≠ 0,且满足x = X / Z,y = Y / Z(或其他等价变换,具体形式取决于坐标系定义)。这一变换的核心是用乘法和加法替代除法:通过将仿射坐标中的除法转化为射影坐标中对Z分量的乘法操作,避免了计算逆元的高成本步骤,尤其在有限域等代数结构中能显著提升运算效率。

1.4.1 标准射影坐标(Standard Projective Coordinates,简称P3)

定义:对于仿射点(x, y),射影坐标表示为(X, Y, Z),满足:x = X/Z,y = Y/Z,其中Z ≠ 0。
等价性:若λ ≠ 0,则(X, Y, Z)与(λX, λY, λZ)表示同一个仿射点(即坐标具有齐次性)。
1.4.2 雅可比射影坐标(Jacobian Projective Coordinates,简称J3)

定义:为进一步优化椭圆曲线运算(尤其是点加倍)而设计,满足:x = X/Z2,y = Y/Z3,其中Z ≠ 0。
优势:在椭圆曲线的点加倍运算中,能减少乘法和平方操作的次数,是 ECC 实现中最常用的坐标形式之一。
2 公式推导

由于secp256k1射影坐标用的是雅可比坐标,所以只介绍其公式推导。
2.1 倍点公式推导

雅可比坐标用(X, Y, Z)表示仿射坐标(x, y) = (X/Z2, Y/Z3),需要将仿射坐标得倍点公式转换为雅可比坐标。
2.1.1 将斜率用雅可比表示

仿射斜率:

2.1.2 计算X3, Y3, Z3

将以上以及x1雅可比表示代入公式(3)中有:

进一步进行通分得:

同理由公式(4)可得:

观察以上两式,只要令:

则有x3 = X3/Z32,y3 = Y3/Z33,完全满足推导出来的等式,所以以上即雅可比倍点公式。
2.1.3 优化计算步骤

计算中间变量:

则X3,Y3,Z3由以下计算公式给出:

其实以上D=4X1​Y12,该计算方式只有在(X1​+B)2比单独计算 X1⋅B更快才有价值,否则可直接使用无D版本公式:

对于secp256k1来说因为a=0,所以hyperelliptic.org给出了两种简化后的计算对比,M:乘法(Multiplication),指有限域上的元素乘法操作;S:平方(Squaring),指有限域上的元素平方操作(通常比一般乘法成本低,故单独统计);add:加法(Addition),指有限域上的元素加法或减法操作(成本较低,有时可忽略,但此处单独列出);3*2、1*3、1*8:表示特定常数乘法的次数(如乘以常数 2、3、8 的操作,这类操作可通过优化实现,成本通常低于一般乘法)。因此,第一个公式表示该算法共需:2次乘法 + 5次平方 + 6次加法 + 3次乘以2的操作 + 1次乘以3的操作 + 1次乘以8的操作。

2.2 点加公式推导

2.2.1 x3雅可比坐标表示

雅可比坐标用(X, Y, Z)表示仿射坐标(x, y) = (X/Z2, Y/Z3),将雅可比表示的坐标直接代入公式(1)可知:

2.2.2 y3雅可比坐标表示

求y3时,由于:y3 = λ(x1 - x3) - y1   且    y3 = λ(x2 - x3) - y2,等式两侧分别相加可知:

等式两边除于2即得y3。
2.2.3 两点和公式

观察以上得出x3和y3表达式,只要令:

则有:

为了使得计算流程更为清晰,可引入如下中间变量:

则求解公式可简化为:

对于secp256k1来说因为a=0,hyperelliptic.org给出详细的计算复杂度,如下所示:

 在源码中使用的正是add-1998-cmo方法,很容易验算它和add-1986-cc方法是一致的。
2.3 统一倍点及点和公式

2.3.1 侧信道攻击 

维基百科是这么定义的:“在密码学中,侧信道攻击(Side-channel attack)是一种攻击方式,它基于从密码系统的物理实现中获取的信息,而非暴力破解法或是算法中的理论性缺陷,例如利用时间信息、功率消耗、电磁泄露或甚是声音可以提供额外的信息,来对系统的破解”。简单一点理解就是利用一些“旁门左道”的手法来获取我们需要的机密信息;比如经常在电视剧中看到的一个场景:一个窃贼将听诊器压在保险柜的前面板上,通过内部的机械声来打开保险柜。小偷会慢慢地转动转盘,听着内部机械结构所泄露出的咔哒声或阻力声,来分析保险箱齿轮的内部运作,并从而得知其密码的组合。除了拨号盘上的数字和保险柜“是”或“否”的打开状态以外,这个保险柜并不会给用户任何反馈,但保险箱的物理机械所产生的那些微小的触动和声音线索,这也是一个典型的侧信道攻击。
SPA-Like Attacks 通常是指类似简单功率分析(Simple Power Analysis,SPA)的攻击方式。SPA 是一种侧信道攻击方法,它通过分析密码设备在运行过程中的功率消耗情况,来获取设备操作和密钥等信息。其攻击原理是:密码设备在执行不同操作时,其功率消耗会有所不同。例如,乘法运算通常比加法运算消耗更多的功率,对不同数据的处理也会导致不同的功率消耗模式。攻击者通过测量密码设备的功率消耗,观察其功率波形,就可以推断出设备正在执行的操作,进而分析出密钥等敏感信息。在椭圆曲线密码体制中,标量乘算法常采用 “倍点 - 点加” 算法。由于倍点和点加运算的时间和消耗能量不同,攻击者可以通过分析功率波形,识别出这两种运算,从而获取关于标量(通常与密钥相关)的信息,对椭圆曲线密码系统构成威胁。标量乘法算法如下,如果从功率追踪显示倍点运算后又进行了一次加法运算,则当前位ki应该等于1,否则等于0。

2.3.2 统一公式

分析倍点及点和公式,它们最大的不同就在于关联直线(“chord-and-tangent”弦与切线)的斜率λ表示不同,如果能用相同的公式表达λ,则公式(1)、(2)和公式(3)、(4)就能统一起来。
首先给出一个基于一般维尔斯特拉斯方程的命题:E是基于域K的椭圆曲线,其方程为:y2 + a1xy + a3y = x3 + a2x2 + a4x + a6,同样P = (x1, y1),Q = (x2, y2)是椭圆曲线上的点,且y(P) ≠ y(-Q)(保证两点不关于曲线对称,避免点加退化为倍点或无穷远点),令P + Q = (x3, y3),则有:

下面给出以上结论的证明过程,对于Q(x2, y2)假设其负元-Q坐标为(x', y'),则有x'=x2,即它们是直线x=x2和椭圆曲线的两个交点,将直线方程代入椭圆方程,并将其看作是关于y的一元二次方程,由韦达定理可知y2+y'=-a1x2 - a3,即y' = -y2 - a1x2 - a3,所以条件y(P) ≠ y(-Q)等价于y1 ≠  -y2 - a1x2 - a3,首先看下P ≠ Q时λ推导过程:


假如P = Q,则可以将x2用x1取代,y2用y1取代,则上述λ公式可以转换为:

这正对于倍点计算时求切线时的求导公式,即已将倍点和点和求斜率的公式统一了起来。进而,对于椭圆曲线y2 = x3 + ax + b来说,统一公式可以简化为:

对于secp256k1来说,统一公式可进一步将a忽略。
3 源码分析

本节给出典型函数的源码,并有选择的对函数进行分析。
3.1 secp256k1_gej_double_nonzero

该函数用于执行非零点的倍点计算,第13~14行相当于计算无D版本公式中Z3=2*Y1*Z1;第15~16行求得无D版本公式中E,第17行求得T2=E2,第18行求得B,第19~21行求得8B2,第22~25行求得-2M,第26行求得X3;最后第27~32行给出了Y3。
1 static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a) {
2   /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
3      *
4      * Note that there is an implementation described at
5      *   https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
6      * which trades a multiply for a square, but in practice this is actually slower,
7      * mainly because it requires more normalizations.
8      */
9   secp256k1_fe t1,t2,t3,t4;
10
11   r->infinity = 0;
12
13   secp256k1_fe_mul(&r->z, &a->z, &a->y);
14   secp256k1_fe_mul_int(&r->z, 2);       /* Z' = 2*Y*Z (2) */
15   secp256k1_fe_sqr(&t1, &a->x);
16   secp256k1_fe_mul_int(&t1, 3);         /* T1 = 3*X^2 (3) */
17   secp256k1_fe_sqr(&t2, &t1);         /* T2 = 9*X^4 (1) */
18   secp256k1_fe_sqr(&t3, &a->y);
19   secp256k1_fe_mul_int(&t3, 2);         /* T3 = 2*Y^2 (2) */
20   secp256k1_fe_sqr(&t4, &t3);
21   secp256k1_fe_mul_int(&t4, 2);         /* T4 = 8*Y^4 (2) */
22   secp256k1_fe_mul(&t3, &t3, &a->x);    /* T3 = 2*X*Y^2 (1) */
23   r->x = t3;
24   secp256k1_fe_mul_int(&r->x, 4);       /* X' = 8*X*Y^2 (4) */
25   secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */
26   secp256k1_fe_add(&r->x, &t2);         /* X' = 9*X^4 - 8*X*Y^2 (6) */
27   secp256k1_fe_negate(&t2, &t2, 1);   /* T2 = -9*X^4 (2) */
28   secp256k1_fe_mul_int(&t3, 6);         /* T3 = 12*X*Y^2 (6) */
29   secp256k1_fe_add(&t3, &t2);         /* T3 = 12*X*Y^2 - 9*X^4 (8) */
30   secp256k1_fe_mul(&r->y, &t1, &t3);    /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */
31   secp256k1_fe_negate(&t2, &t4, 2);   /* T2 = -8*Y^4 (3) */
32   secp256k1_fe_add(&r->y, &t2);         /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
33 }之后的secp256k1_gej_double_var函数正式调用了该函数实现倍点操作,只不过在secp256k1_gej_double_var函数中对无穷远点做了特殊处理。
3.2 secp256k1_gej_add_var

 2.2节已经详细分析了公式推导相关过程,所以不再对该函数进行详细分析,请根据注释自行理解。
1 /*
2 * lambda1 = x1*z2^2
3 * lambda2 = x2*z1^2
4 * lambda3 = lambda2 - lambda1
5 * lambda4 = y1*z2^3
6 * lambda5 = y2*z1^3
7 * lambda6 = lambda5 - lambda4
8 * lambda7 = lambda1 + lambda2
9 * lambda8 = lambda4 + lambda5
10 * x3 = lambda6^2 - (2*lambda1*lambda3^2 + lambda3^3)
11 * lambda9 = lambda7*lambda3^2 - 2*x3
12 * y3 = (lambda5 - lambda4)*(lambda1*lambda3^2 - x3) - lambda4*lambda3^3
13 * z3 = z1*z2*lambda3
14 */
15 static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
16   /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */
17   secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
18
19   if (a->infinity) {
20         *r = *b;
21         return;
22   }
23
24   if (b->infinity) {
25         if (rzr != NULL) {
26             secp256k1_fe_set_int(rzr, 1);
27         }
28         *r = *a;
29         return;
30   }
31
32   r->infinity = 0;
33   secp256k1_fe_sqr(&z22, &b->z);
34   secp256k1_fe_sqr(&z12, &a->z);
35   secp256k1_fe_mul(&u1, &a->x, &z22);      // u1=lambda1
36   secp256k1_fe_mul(&u2, &b->x, &z12);      // u2=lambda2
37   
38   secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z);    // s1=lambda4
39   secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);    // s2=lambda5
40   secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);      // lambda3
41   secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);      // i=lambda6
42   if (secp256k1_fe_normalizes_to_zero_var(&h)) {
43         if (secp256k1_fe_normalizes_to_zero_var(&i)) {
44             secp256k1_gej_double_var(r, a, rzr);
45         } else {
46             if (rzr != NULL) {
47               secp256k1_fe_set_int(rzr, 0);
48             }
49             r->infinity = 1;
50         }
51         return;
52   }
53   secp256k1_fe_sqr(&i2, &i);            // i2=lambda6^2
54   secp256k1_fe_sqr(&h2, &h);            // h2=lambda3^2
55   secp256k1_fe_mul(&h3, &h, &h2);    // h3=lambda3^3
56   secp256k1_fe_mul(&h, &h, &b->z);    // Z2*lambda3
57   if (rzr != NULL) {
58         *rzr = h;
59   }
60   secp256k1_fe_mul(&r->z, &a->z, &h);    // Z1*Z2*lambda3
61   secp256k1_fe_mul(&t, &u1, &h2);      // t=lambda1*lambda3^2
62   r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
63   secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
64   secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
65   secp256k1_fe_add(&r->y, &h3);
66 }3.3  secp256k1_gej_add_ge

该函数用于计算射影坐标和仿射坐标相加,由2.3节可知统一公式如下:

代入x1=X1/Z12,y1=Y1/Z13,x2=X2/Z22,y2=Y2/Z23,可得:



函数源码如下:
1 static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) {
2   /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */
3   static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
4   secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
5   secp256k1_fe m_alt, rr_alt;
6   int infinity, degenerate;
7   if (b->infinity) {
8         *r = *a;
9         return;
10   }
11
12   /** In:
13      *    Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks.
14      *    In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002.
15      *we find as solution for a unified addition/doubling formula:
16      *    lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation.
17      *    x3 = lambda^2 - (x1 + x2)
18      *    2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2).
19      *
20      *Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives:
21      *    U1 = X1*Z2^2, U2 = X2*Z1^2
22      *    S1 = Y1*Z2^3, S2 = Y2*Z1^3
23      *    Z = Z1*Z2
24      *    T = U1+U2
25      *    M = S1+S2
26      *    Q = T*M^2
27      *    R = T^2-U1*U2
28      *    X3 = 4*(R^2-Q)
29      *    Y3 = 4*(R*(3*Q-2*R^2)-M^4)
30      *    Z3 = 2*M*Z
31      *(Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.)
32      *
33      *This formula has the benefit of being the same for both addition
34      *of distinct points and doubling. However, it breaks down in the
35      *case that either point is infinity, or that y1 = -y2. We handle
36      *these cases in the following ways:
37      *
38      *    - If b is infinity we simply bail by means of a VERIFY_CHECK.
39      *
40      *    - If a is infinity, we detect this, and at the end of the
41      *      computation replace the result (which will be meaningless,
42      *      but we compute to be constant-time) with b.x : b.y : 1.
43      *
44      *    - If a = -b, we have y1 = -y2, which is a degenerate case.
45      *      But here the answer is infinity, so we simply set the
46      *      infinity flag of the result, overriding the computed values
47      *      without even needing to cmov.
48      *
49      *    - If y1 = -y2 but x1 != x2, which does occur thanks to certain
50      *      properties of our curve (specifically, 1 has nontrivial cube
51      *      roots in our field, and the curve equation has no x coefficient)
52      *      then the answer is not infinity but also not given by the above
53      *      equation. In this case, we cmov in place an alternate expression
54      *      for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these
55      *      expressions for lambda are defined, they are equal, and can be
56      *      obtained from each other by multiplication by (y1 + y2)/(y1 + y2)
57      *      then substitution of x^3 + 7 for y^2 (using the curve equation).
58      *      For all pairs of nonzero points (a, b) at least one is defined,
59      *      so this covers everything.
60      */
61
62   secp256k1_fe_sqr(&zz, &a->z);                     /* z = Z1^2 */
63   u1 = a->x; secp256k1_fe_normalize_weak(&u1);      /* u1 = U1 = X1*Z2^2 (1) */
64   secp256k1_fe_mul(&u2, &b->x, &zz);                  /* u2 = U2 = X2*Z1^2 (1) */
65   s1 = a->y; secp256k1_fe_normalize_weak(&s1);      /* s1 = S1 = Y1*Z2^3 (1) */
66   secp256k1_fe_mul(&s2, &b->y, &zz);                  /* s2 = Y2*Z1^2 (1) */
67   secp256k1_fe_mul(&s2, &s2, &a->z);                  /* s2 = S2 = Y2*Z1^3 (1) */
68   t = u1; secp256k1_fe_add(&t, &u2);                  /* t = T = U1+U2 (2) */
69   m = s1; secp256k1_fe_add(&m, &s2);                  /* m = M = S1+S2 (2) */
70   secp256k1_fe_sqr(&rr, &t);                        /* rr = T^2 (1) */
71   secp256k1_fe_negate(&m_alt, &u2, 1);                /* Malt = -X2*Z1^2 */
72   secp256k1_fe_mul(&tt, &u1, &m_alt);               /* tt = -U1*U2 (2) */
73   secp256k1_fe_add(&rr, &tt);                         /* rr = R = T^2-U1*U2 (3) */
74   /** If lambda = R/M = 0/0 we have a problem (except in the "trivial"
75      *case that Z = z1z2 = 0, and this is special-cased later on). */
76   degenerate = secp256k1_fe_normalizes_to_zero(&m) &
77                  secp256k1_fe_normalizes_to_zero(&rr);
78   /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2.
79      * This means either x1 == beta*x2 or beta*x1 == x2, where beta is
80      * a nontrivial cube root of one. In either case, an alternate
81      * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2),
82      * so we set R/M equal to this. */
83   rr_alt = s1;
84   secp256k1_fe_mul_int(&rr_alt, 2);       /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */
85   secp256k1_fe_add(&m_alt, &u1);          /* Malt = X1*Z2^2 - X2*Z1^2 */
86
87   secp256k1_fe_cmov(&rr_alt, &rr, !degenerate);
88   secp256k1_fe_cmov(&m_alt, &m, !degenerate);
89   /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0.
90      * From here on out Ralt and Malt represent the numerator
91      * and denominator of lambda; R and M represent the explicit
92      * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
93   secp256k1_fe_sqr(&n, &m_alt);                     /* n = Malt^2 (1) */
94   secp256k1_fe_mul(&q, &n, &t);                     /* q = Q = T*Malt^2 (1) */
95   /* These two lines use the observation that either M == Malt or M == 0,
96      * so M^3 * Malt is either Malt^4 (which is computed by squaring), or
97      * zero (which is "computed" by cmov). So the cost is one squaring
98      * versus two multiplications. */
99   secp256k1_fe_sqr(&n, &n);
100   secp256k1_fe_cmov(&n, &m, degenerate);            /* n = M^3 * Malt (2) */
101   secp256k1_fe_sqr(&t, &rr_alt);                      /* t = Ralt^2 (1) */
102   secp256k1_fe_mul(&r->z, &a->z, &m_alt);             /* r->z = Malt*Z (1) */
103   infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity);
104   secp256k1_fe_mul_int(&r->z, 2);                     /* r->z = Z3 = 2*Malt*Z (2) */
105   secp256k1_fe_negate(&q, &q, 1);                     /* q = -Q (2) */
106   secp256k1_fe_add(&t, &q);                           /* t = Ralt^2-Q (3) */
107   secp256k1_fe_normalize_weak(&t);
108   r->x = t;                                           /* r->x = Ralt^2-Q (1) */
109   secp256k1_fe_mul_int(&t, 2);                        /* t = 2*x3 (2) */
110   secp256k1_fe_add(&t, &q);                           /* t = 2*x3 - Q: (4) */
111   secp256k1_fe_mul(&t, &t, &rr_alt);                  /* t = Ralt*(2*x3 - Q) (1) */
112   secp256k1_fe_add(&t, &n);                           /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */
113   secp256k1_fe_negate(&r->y, &t, 3);                  /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */
114   secp256k1_fe_normalize_weak(&r->y);
115   secp256k1_fe_mul_int(&r->x, 4);                     /* r->x = X3 = 4*(Ralt^2-Q) */
116   secp256k1_fe_mul_int(&r->y, 4);                     /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */
117
118   /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */
119   secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
120   secp256k1_fe_cmov(&r->y, &b->y, a->infinity);
121   secp256k1_fe_cmov(&r->z, &fe_1, a->infinity);
122   r->infinity = infinity;
123 }注释中第22~30行正是由之前的公式而来,源码中参数b是一个仿射坐标的曲线点(x2, y2),其对应雅可比射影坐标可表示为(x2, y2, 1)。源码第33~59行注释说了如何对4中特殊情况进行处理的,尤其是第4中情况degenerate case,它特指如下情形:

下图展示了一个典型的secp256k1椭圆曲线 y2=x3+7中的退化情况示例,P和Q满足以上1和3两个条件,却在实数域中不可能满足第2个条件,但是有限域Fp​中该条件却有可能成立,所以代码中也把这种情况考虑进去了,其他特殊情况比较显而易见,不再详细说明。

参考:

weierstrass elliptic curves and side-channel attacks
https://blog.csdn.net/qq_50680426/article/details/120940244

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: secp256k1算法详解三(点操作关键理论及源码分析)