如何用椭圆曲线上的雅可比坐标系计算点加法

时间:2011-12-05 17:28:28

标签: cryptography coordinate-systems elliptic-curve

我正在编写一个椭圆曲线加密的小项目,当我使用仿射坐标系时程序运行良好,这意味着每个点由2个坐标(x',y')表示。

现在我试图用雅可比坐标系代替仿射坐标系,其中每个点由3个坐标(x,y,z),x'= x /z²和y'= y /z³表示。

我想知道如何将仿射坐标转换为雅可比坐标**。在一些教程中,人们使用公式:(x,y)=(x,y,1) 这意味着z坐标始终设置为1。但我不确定它是否正确。

然后,对于椭圆曲线上的点加法,计算P(x1,y1,z1)+ Q(x2,y2,z2)= R(x3,y3,z3)。我在我的程序中使用了以下公式:

u1 = x1.z2²
u2 = x2.z1²
s1 = y1.z2³
s2 = y2.z1³
h = u2 - u1
r = s2 - s1
x3 = r² - h³ - 2.u1.h²
Y3 = r. (U1.h² - x3) - s1.h³
z3 = z1.z2.h

但是当我测试我的程序时,我会得到一些负坐标,例如(-2854978200,-5344897546224,578)。当我尝试使用公式(x'= x /z²,y'= y /z³)将结果转换回仿射坐标系时,我得到(-8545,-27679),实际上x坐标是-8545.689。 ...雅各比x坐标不能被z²整除。

如果坐标不是整数,我该怎么办?如果他们是消极的?我尝试用我的曲线的字段大小来修改MOD,但结果也不正确。

所以使用雅可比坐标(x,y,1)的观点是正确的,但不是唯一的。满足(a^2.x,a^3.y,a)的所有点都是等价的。在我的程序中,曲线是在素数域中定义的,所以当我计算u1, u2, s1, s2 ...时,我应该将MO​​D p应用于每个变量吗?

用于将最终结果转换回仿射坐标,例如x坐标,实际上它不是一个除法,它是模块化逆?例如,我的曲线是在有限素数域p=11中定义的,我有一个点使用雅可比坐标(15,3,2),要将jacobian x坐标转换为仿射x坐标,我必须计算2^2 = 4 => x = 4^-1 mod p => x = 315.3 mod p = 1,因此仿射x坐标为1,是吗?

雅可比坐标的目的是避免在加法时划分。但正如Thomas Pornin所说,当我们计算P1 + P2 = P3时,有一些特殊情况要处理。

  1. P1和P2都是无限的:P3=infinite
  2. P1无限:P3=P2
  3. P2无限:P3=P1
  4. P1和P2具有相同的x坐标,但不同的y坐标或两个y坐标均等于0:P3=infinite
  5. P1和P2具有不同的x坐标:Addition formula
  6. P1和P2具有相同的坐标:Doubling formula
  7. 这是我的C函数的原型:

    jac_addition(jacobian *, point *, jacobian *);
    jac_doubling(jacobian *, jacobian *);
    

    point是一个结构,表示在仿射坐标系中定义的点,jacobian表示雅可比系统。

    问题是,当我处理这些特殊情况时,特别是第4个,我仍然将两个点转换回仿射坐标,或者我无法比较它们的坐标,这意味着我仍然需要计算除法。

3 个答案:

答案 0 :(得分:8)

投影坐标的雅可比形式(与任何其他形式一样)不是唯一的 - 对于Z(除了0)的每个值,您得到的是其他XY而没有实际点变化。

因此,如果您在仿射坐标(X', Y')中有一个点,则对(X', Y', 1)是此点的投影代表,以及(4·X', 8·Y', 2)(9·X', 27·Y', 3)等带1的那个是最容易创建的,所以通常你会使用这个。

虽然可以在任何字段上定义(和研究)椭圆曲线,并且许多数学家研究在复数上定义的曲线,但对于加密用途,坐标是某些有限域的元素。在最简单的情况下,我们有一个素数场(即以素数为模的整数),你将不得不在这个场中进行加法,减法,乘法和除法(以及可能取幂)。

只要Z不为零,你应该能够除以 - 这相当于乘以Z²的倒数,并且这样的元素存在,并且可以有效地计算使用扩展的欧几里德算法。

如果您的编程语言带有一些预定义必要操作的大数字库,这是最简单的,例如Java的BigInteger类(带有modmodPow和{{1}方法)。

所讨论的字段(即模数)是椭圆曲线定义的一部分,并且对一个字段的操作给出与另一个字段中的操作完全不同的结果。因此,请确保使用正确的字段。

答案 1 :(得分:2)

处理椭圆曲线时,坐标位于field。对于加密,这是finite field;在你的情况下,“整数模数为 p ”。 所有操作都在该字段中,即您应该每次添加,乘法或反转模 p

在添加积分时,有一些特殊情况需要特别处理:

  • 有一个特殊的“无限远点”,它没有坐标 x y 。它是曲线加法的“零”。在通用的点添加例程中,您必须有一种方法来编码“无穷远点”并对其进行特殊检查。

  • (x,y)添加到(x',y')时,可能会发生 x = x'。在这种情况下, y = y',然后它是点加倍,它有其特定的公式(如果你应用通用公式,你最终除以零,这将无效);或者, y = -y',在这种情况下,总和是“无限远点”。

因此,只有处理完特殊情况后才能应用通用公式。一般来说,在曲线 y 2 = x 3 + a·x + b 中,的总和(x 1 ,y 1 (x 2 ,y 2 (x 3 ,y 3 ,使 x 3 = f 2 < / sup> -x 1 -x 2 y 3 = f·(x 1 < / sub> -x 3 ) - y 1 ,其中 f =(y 2 -y 1 )/(X <子> 2 -x <子> 1 。这意味着计算一个除法和两个乘法,以及一些减法(所有操作都在模数 p 的整数上完成,如上所述)。

分割和反演模 p 相对昂贵(模块化除法通常具有与大约80次乘法相同的成本),因此在某些情况下,我们使用投影或雅可比坐标系。雅可比坐标是将一个点表示为三个值(X,Y,Z)(所有这些都在有限域中,即整数模 p ),这样 x = X / Z 2 y = Y / Z 3

每个点(x,y)都有许多可能的表示形式为(X,Y,Z)。通过设置 X = x Y = y Z = 1 ,可以轻松将转换为雅可比坐标:(x,y,1)(x,y)点的完全有效的雅可比表示。从雅可比坐标转换在计算上更难:你必须进行模块化反演,并进行一些乘法(你计算 U = 1 / Z ,然后 x = X ·U 2 y = Y·U 3 )。

使用雅可比坐标,在十几个场乘法中增加两个点,完全没有除法。你只得到结果的雅可比表示,所以你仍然需要在某个时刻进行模块化反演或除法; 然而(这就是你使用雅可比坐标的原因),这种划分可以互相共存。如果你必须进行大约一百次连续的点加法(在加密上下文中通常,当一个点与一个整数“相乘”时),那么你可以在整个过程中使用雅可比表示,并进行一次转换回笛卡尔坐标< em>(x,y)结尾。因此,不进行200次乘法和100次除法,而是进行1000次乘法和1次反演;由于反演的成本与80次乘法相同,因此增益很明显。

尽量利用this book;任何好的大学图书馆都应该有一个。它非常清楚地解释了所有这些。

答案 2 :(得分:0)

这是python中的示例:

def to_jacobian((Xp, Yp)):
    """
    Convert point to Jacobian coordinates

    :param (Xp,Yp,Zp): First Point you want to add
    :return: Point in Jacobian coordinates
    """
    return (Xp, Yp, 1)

def from_jacobian((Xp, Yp, Zp), P):
    """
    Convert point back from Jacobian coordinates

    :param (Xp,Yp,Zp): First Point you want to add
    :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p)
    :return: Point in default coordinates
    """
    z = inv(Zp, P)
    return ((Xp * z**2) % P, (Yp * z**3) % P)

def jacobian_add((Xp, Yp, Zp), (Xq, Yq, Zq), A, P):
    """
    Add two points in elliptic curves

    :param (Xp,Yp,Zp): First Point you want to add
    :param (Xq,Yq,Zq): Second Point you want to add
    :param P: Prime number in the module of the equation Y^2 = X^3 + A*X + B (mod p)
    :param A: Coefficient of the first-order term of the equation Y^2 = X^3 + A*X + B (mod p)
    :return: Point that represents the sum of First and Second Point
    """
    if not Yp:
        return (Xq, Yq, Zq)
    if not Yq:
        return (Xp, Yp, Zp)
    U1 = (Xp * Zq ** 2) % P
    U2 = (Xq * Zp ** 2) % P
    S1 = (Yp * Zq ** 3) % P
    S2 = (Yq * Zp ** 3) % P
    if U1 == U2:
        if S1 != S2:
            return (0, 0, 1)
        return jacobian_double((Xp, Yp, Zp), A, P)
    H = U2 - U1
    R = S2 - S1
    H2 = (H * H) % P
    H3 = (H * H2) % P
    U1H2 = (U1 * H2) % P
    nx = (R ** 2 - H3 - 2 * U1H2) % P
    ny = (R * (U1H2 - nx) - S1 * H3) % P
    nz = (H * Zp * Zq) % P
    return (nx, ny, nz)

所以您可以总结为:

def fast_add(a, b, A, P):
    return from_jacobian(jacobian_add(to_jacobian(a), to_jacobian(b), A, P), P)