我正在编写一个椭圆曲线加密的小项目,当我使用仿射坐标系时程序运行良好,这意味着每个点由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 ...
时,我应该将MOD p应用于每个变量吗?
用于将最终结果转换回仿射坐标,例如x坐标,实际上它不是一个除法,它是模块化逆?例如,我的曲线是在有限素数域p=11
中定义的,我有一个点使用雅可比坐标(15,3,2)
,要将jacobian x坐标转换为仿射x坐标,我必须计算2^2 = 4 => x = 4^-1 mod p => x = 3
和15.3 mod p = 1
,因此仿射x坐标为1,是吗?
雅可比坐标的目的是避免在加法时划分。但正如Thomas Pornin所说,当我们计算P1 + P2 = P3
时,有一些特殊情况要处理。
P3=infinite
。P3=P2
。P3=P1
。P3=infinite
。Addition formula
。Doubling formula
。这是我的C函数的原型:
jac_addition(jacobian *, point *, jacobian *);
jac_doubling(jacobian *, jacobian *);
point
是一个结构,表示在仿射坐标系中定义的点,jacobian
表示雅可比系统。
问题是,当我处理这些特殊情况时,特别是第4个,我仍然将两个点转换回仿射坐标,或者我无法比较它们的坐标,这意味着我仍然需要计算除法。
答案 0 :(得分:8)
投影坐标的雅可比形式(与任何其他形式一样)不是唯一的 - 对于Z
(除了0)的每个值,您得到的是其他X
和Y
而没有实际点变化。
因此,如果您在仿射坐标(X', Y')
中有一个点,则对(X', Y', 1)
是此点的投影代表,以及(4·X', 8·Y', 2)
,(9·X', 27·Y', 3)
等带1的那个是最容易创建的,所以通常你会使用这个。
虽然可以在任何字段上定义(和研究)椭圆曲线,并且许多数学家研究在复数上定义的曲线,但对于加密用途,坐标是某些有限域的元素。在最简单的情况下,我们有一个素数场(即以素数为模的整数),你将不得不在这个场中进行加法,减法,乘法和除法(以及可能取幂)。
只要Z
不为零,你应该能够除以Z²
- 这相当于乘以Z²的倒数,并且这样的元素存在,并且可以有效地计算使用扩展的欧几里德算法。
如果您的编程语言带有一些预定义必要操作的大数字库,这是最简单的,例如Java的BigInteger
类(带有mod
,modPow
和{{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)