椭圆曲线上的加法


29

椭圆曲线上的加法

免责声明:这对椭圆曲线这一丰富话题没有任何根据。它简化了很多。由于椭圆曲线最近在加密方面引起了媒体的广泛关注,我想提供一些小见识,以了解如何在椭圆曲线上进行“计算”实际上是如何工作的。

介绍

椭圆曲线是(x,y)表单平面中的点集y^2 = x^3+Ax+B。(此外,4A^3+27B^2 ≠ 0为了避免令人讨厌的奇异性。)您可以在任何字段中考虑这些曲线。如果使用实数字段,则曲线可以可视化,看起来像这样:

椭圆曲线的两个例子
资源

这些曲线的特殊之处在于它们具有内置的算术运算,类似于加法运算。您可以添加和减去点,并且此操作既是关联的又是交换的(阿贝尔群)。

加法如何工作?

注意:在椭圆曲线上添加点并不直观。之所以定义这种加法,是因为它具有某些不错的属性。很奇怪,但是行得通。

当椭圆曲线形成一个组时,存在一个等于0 的加法标识。也就是说,添加0到任何点都不会改变结果。此加性标识是无穷大的“点”。平面上的所有线都在无穷远处包含此点,因此添加它没有区别。

假设任何给定的线在三个点处可能与曲线相交0,而这三个点的总和为0。牢记这一点,请看一下这张图片。

椭圆曲线加法特例
资源

现在,自然的问题是,什么是P+Q?好吧,如果是P+Q+R = 0,那么P+Q = -R(或者写成R')。哪里-R呢 它是其中R + (-R) = 0,这是在x轴的另一侧,从R使得通过它们的行是垂直的,只有相交R-R以及0。您可以在此图像的第一部分看到这一点:

椭圆曲线上的各种加法图 资源

您可以在这些图像中看到的另一件事是,一个点与自身的总和意味着该线与曲线相切。

如何找到直线和椭圆曲线的交点

在两个不同点的情况下

通常,只有一条直线穿过两点P=(x0,y0), Q=(x1,y1)。假设它不是垂直的并且两个点是不同的,我们可以将其写为y = m*x+q。当我们想找到与椭圆曲线的交点时,我们可以写成

0 = x^3+Ax+B-y^2 = x^3+Ax+B-(m*x+q)^2

这是三次多项式。这些通常不那么容易求解,但是我们已经知道该多项式的两个零:我们要相加的两个点的两个x坐标x0, x1

这样,我们就可以分解出线性因子(x-x0)(x-x1)并且剩下第三个线性因子,其根是x点的-坐标R。(-R。因为太多的对称性,请注意,如果R = (x2,y2)随后-R = (x2,-y2)的。-从该组;它不是一个矢量负)。

如果P自己加一点

在这种情况下,我们必须计算处的曲线的切线P=(x0,y0)。我们可以直接写入m,并q在以下方面A,B,x0,y0

     3*x0^2 + A
m = ------------
        2*y0

     -x0^3 + A*x0 + 2*B
q = --------------------
          2*y0

我们得到了等式,y = m*x+q并且可以按照与上段相同的方式进行。

完整的案例树

这是如何处理所有这些情况的完整列表:

P,Q为椭圆曲线上的点(包括“无穷大”点0

  • 如果P = 0Q = 0,则分别为P+Q = QP+Q = P
  • 否则P ≠ 0Q ≠ 0,让我们P = (x0,y0)Q = (x1,y1)
    • 如果P = -Q(表示x0 = x1y0 = -y1)则P+Q = 0
    • 其他 P ≠ -Q
      • 如果x0 = x1P=Q,我们就可以计算出切线(见上文)R。然后P+Q = P+P = 2P = -R
      • 否则:我们可以y = m*x+y通过这两点构造一个形式的线(请参见上文)以进行计算R。然后P+Q=-R

有限域

对于这个挑战,我们将只考虑大小的领域p,其中p为素数(因为一些细节p ≠ 2, p ≠ 3)。这样的好处是您可以简单地进行计算mod p。其他领域的算法要复杂得多。

在本示例中,我们设置了此示例p = 5,此处的所有等式都是等价的mod 5

2+4 ≡ 6 ≡ 1
2-4 ≡ -2 ≡ 3
2*4 ≡ 8 ≡ 3
2/4 ≡ 2*4 ≡ 3 because 4*4 ≡ 16 ≡ 1, therefore 1/4 ≡ 4

挑战

给定A,B椭圆曲线的参数,素场特性pP,Q椭圆曲线上的两个点,将其求和。

  • 您可以假设参数A,B实际上描述了一条椭圆曲线,这意味着4A^3+27B^2 ≠ 0
  • 您可以假定P,Q实际上是椭圆曲线或0-point上的点。
  • 您可以假设p ≠ 2,3是素数。

测试用例

我在MATLAB / Octave中实现了一个(不是很好)的实现,可以将其用于自己的测试用例:ideone.com,我希望它是正确的。它至少重现了我手工进行的一些计算。

请注意我们在这里考虑的适用于所有曲线的琐碎测试用例:

加零:P+0 = P 加逆:(x,y) + (x,-y) = 0


对于p = 7, A = 0, B = 5两个点P = (3,2)Q = (6,2)分别在椭圆曲线上。然后成立:

2*Q = Q+Q = P
2*P = P+P = (5,2)
3*P = P+P+P = (5,2)+P = (6,5)
4*P = P+P+P+P = (5,2)+(5,2) = (6,5)+(5,2) = Q

椭圆曲线上的所有点都是 (3,2),(5,2),(6,2),(3,5),(5,5),(6,5),0


因为p = 13, A = 3, B = 8我们得到

(1,8)+(9,7) = (2,10)
(2,3)+(12,11) = (9,7)
2*(9,6) = (9,7)
3*(9,6) = 0

对于p = 17, A = 2, B = 2P=(5,1) 我们得到

2*P = (6,3)
3*P = (10,6)
4*P = (3,1)
5*P = (9,16)
6*P = (16,13)
7*P = (0,6)
8*P = (13,7)
9*P = (7,6)
10*P = (7,11)

如果您真的有雄心壮志,

p = 1550031797834347859248576414813139942411
A = 1009296542191532464076260367525816293976
x0 = 1317953763239595888465524145589872695690
y0 = 434829348619031278460656303481105428081
x1 = 1247392211317907151303247721489640699240
y1 = 207534858442090452193999571026315995117

并尝试找到一个n这样的自然数n*(x0,y0) = (x1,y1)此处有更多信息。

附录

首先,非常感谢@ El'endiaStarman审核和编辑我的草稿!

为什么是椭圆曲线?

好吧,它看起来像某种任意方程式,但事实并非如此,它很笼统:通常我们考虑投影平面中的那些几何“形状” (也就是“无穷大”的来源。在这里,我们考虑所有齐次的三阶多项式(较低或较高阶的多项式太难或难以研究。)在应用了一些限制以获取我们想要的优良性质之后,并对这些多项式进行了均质化(投影到三个仿射平面之一) )我们最终得到像y^2+a*x*y+b*y = x^3+c*x^2+d*x+e这是长Weierstrass形式的椭圆曲线。这些曲线与我们考虑的基本相同,但有些偏斜。通过线性坐标变换,您可以轻松地生成一个简短的Weierstras方程。example,它仍然包含所有有趣的属性。

我们为什么要排除在外p=2,3

这与以下事实有关:对于简短的Weierstrass形式,我们需要限制条件4A^3+27B^2 ≠ 0以避免奇异性(更多内容见下文)。在特征2 4 = 0的字段中,在特征3的字段中27 = 0,对于这些类型的字段,不可能以短的weierstrass形式形成曲线。

什么是奇点?

如果方程式4A^3+27B^2=0成立,我们将具有如下奇点:如您所见,在这些点上您找不到导数,因此也没有切线,从而“扼杀”了运算。您可能会看方程式y^2 = x^3y^2 = x^3-3*x+2

为什么它们仍被称为椭圆曲线

原因是这种形状的方程会在椭圆积分中弹出,例如,当您要计算椭圆的弧长时,就会得到这些积分。关于名称来源的简短幻灯片。

他们与密码学有什么关系?

有许多方法可以nP = P+P+...+P非常有效地进行计算。例如,这可用于Diffie Hellman密钥交换中。可以用扭转子组上的加法来代替模块化算法,这些子组只是曲线上具有有限阶的点。(这意味着mP = 0对于某些m,基本上只是在计算mod m)。

Answers:


4

Pyth,105 100字节

A,@Q3eQ?qGZH?qHZG?&=YqhHhGqeG%_eHhQZ_m%dhQ,-*J?Y*+*3^hG2@Q1^*2eG-hQ2*-eGeH^-hGhH-hQ2-hGK--^J2hGhHeGK

输入形式应为(p, A, P, Q),,PQ,形式上的两个点;(x, y)或者,如果它们是特殊0点,则与一样0。您可以在这里在线尝试。最后两个示例显示了特殊功能的0工作原理。

为了节省一些字节,我只mod p在最终答案上使用。这意味着它可以执行x0^p几次操作而无需进行模幂运算,因此它可能非常慢。

它的工作原理与此Python函数大致相同:

def add_ellip(p, A, P, Q): # points are in format (x, y)
    z = 0 # representing special 0 point

    if (P == z):
        return Q
    if (Q == z):
        return P

    if P[0] == Q[0]:
        if (P == (Q[0], -Q[1] % p)):
            return z
        else:
            m = ((3*pow(P[0], 2, p) + A)*pow(2*P[1], p-2, p)) % p
    else:
        m = (P[1] - Q[1])*pow(P[0] - Q[0], p-2, p) % p

    x = (pow(m, 2, p) - P[0] - Q[0]) % p
    y = (m*(P[0] - x) - P[1]) % p
    return (x, y)

这在很大程度上取决于以下事实:的模乘逆数x等于x^(p-2) mod pif p是素数。因此,我们能够m通过找到分母的模乘乘法逆并将其乘以分子来计算线的斜率。很方便。由于使用,Python函数应该可以更有效地计算较大的问题pow

我还使用了Wikipedia页面上显示的有关此主题的快捷方式。有趣的是,我最终只使用了A一次,而B不用了。

也只是为了好玩:

def pow2floor(x):
    p = 1
    x >>= 1
    while (x > 0):
        x >>= 1
        p <<= 1
    return p

def multi_nP(p, A, n, P):
    d = {}

    def rec_helper(n, P):
        if (n == 0):
            return (0, 0)
        elif (n == 1):
            return P
        elif (n in d):
            return d[n]
        else:
            p2f = pow2floor(n)
            remainder = n - p2f

            lower_half = rec_helper(p2f//2, P)
            d[p2f//2] = lower_half
            nP = add_ellip(p, A, lower_half, lower_half)

            if (remainder):
                nP = add_ellip(p, A, nP, rec_helper(remainder, P))

            d[n] = nP
            return nP

    return rec_helper(n, P)

multi_nP函数n*P为给定的整数n和point 计算P。它使用分裂递归策略n分为两个部分p2f,并remainder使得p2f + remainder = np2f = 2^k。然后,我们在这些部分上再次调用该函数,并将结果添加到add_ellip。我还通过将已计算的值保存在dict中来使用基本的动态编程方法d

从理论上讲,下一个函数将使用相同的策略解决奖金问题:

def find_nPQ(p, A, P, Q): # P is input point, Q is what we're looking for
    d = {}
    found_Q = False

    def rec_helper(n, P):
        if (n == 0):
            return (0, 0)
        elif (n == 1):
            return P
        elif (n in d):
            return d[n]
        else:
            p2f = pow2floor(n)
            remainder = n - p2f

            lower_half = rec_helper(p2f//2, P)
            d[p2f//2] = lower_half

            nP = add_ellip(p, A, lower_half, lower_half)

            if (remainder):
                nP = add_ellip(p, A, nP, rec_helper(remainder, P))

            d[n] = nP
            return nP


    for x in range(p):
        xP = rec_helper(x, P)
        if (xP == Q):
            return x

不幸的是,它的运行速度远远不足以对其进行计算。我猜测可能会有更有效的方法来执行此操作,尤其是如果我们不必遍历for的每个可能值时,尤其如此n


太好了,老实说我再也没有期待任何答案了=)您如何处理无穷远点?(请注意,这y^2 = x^3 + x是有效的椭圆曲线,并且(0,0) ≠ 0是曲线上的一个点!)
更加模糊的

好问题...我想我没有处理!:P抱歉,我记得看到第一张图片在哪里B = 0,想知道如何0工作...然后我忘记了。我想我以为B昨晚某个时候不能为0。您对输入内容有什么建议吗?也许B = 0,那么定义0 = (-1, -1)?我很高兴调整自己的代码来处理它,我只是认为如果也将其标准化为其他提交内容,
那就

好吧,我把那蓬松的东西打开了,这样提交就可以使用任何方便的方式。但是,您当然可以说,例如曲线上的所有有限点都具有非负坐标,而其他所有点都被视为无穷大点或相似点。或者,如果更简单,您还可以假设输入[0](仅一个坐标)是无穷大点或类似的东西!
瑕疵的

让我知道这是否处理得不够好。谢谢,实际上节省了我5个字节!
Rhyzomatic

@flawr,您能告诉我我是否在正确的方向上进行高效计算nP吗?您能否指出我关于该主题的任何资源以使思想畅通无阻?我很难找到任何Google搜索。谢谢!
Rhyzomatic

0

Python 3中,193个 191字节

一个基于Rhyzomatic的Pyth答案及其Python逻辑的解决方案。特别是。x^3 + bx^2 + cx + d当您有两个根x_1并且x_2注意到b == x_1 + x_2 + x_3并相应减去时,我喜欢他们如何找到单项三次多项式的第三个根。我计划添加一个解释,将其打高尔夫球,或者如果事实证明Ruby更短,则可以将其转换为Ruby。

def e(p,A,B,P,Q):
 if P==0:return Q
 if Q==0:return P
 f,g=P;j,k=Q
 if f==j:
  if g==-k%p:return 0
  m=(3*f*f+A)*pow(2*j,p-2)
 else:m=(g-k)*pow(f-j,p-2)
 x=m*m-f-j;y=m*(f-x)-g;return(x%p,y%p)

开球:

def elliptic_curve_addition(p, A, B, P, Q):
    if P == 0:
        return Q
    if Q == 0:
        return P
    f,q = P
    j,k = Q
    if f==j:
        if g == (-k) % p:
            return 0
        m = (3 * f**2 + A) * pow(2*j, p-2)
    else:
        m = (g-k) * pow(f-j, p-2)
    x = m**2 - f - j
    y = m * (f-x) - g
    return (x%p, y%p)

我很惊讶Python的长度不到Pyth答案的两倍!
瑕疵的2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.