python-3.x - Lenstras 椭圆曲线属性错误问题

标签 python-3.x cryptography attributeerror factorization

已经为 Lenstra elliptic-curve factorization algorithm 编写了一些代码,我对此还算满意。然而,它只在某些时候有效。添加点的函数应返回整数或点。如果它返回整数 d,Lenstra 代码块应该简单地打印 gcd(d,n) 并退出。似乎有时它不会退出,然后尝试将整数放入 add 函数,然后因属性错误而失败。我尝试过修补,但似乎无法纠正。

有人可以告诉我发生了什么事或如何更正代码吗?我很乐意回答任何问题,因为我不是程序员,而且我知道我的代码还很不整洁。

from sympy import mod_inverse
import math
import secrets
from collections import namedtuple
Point = namedtuple("Point", "x y")


def point_valid(P,a,b,p):
    O = 'Inf_Point'
    if P == O:
        return True
    else:
        return (P.y**2 - (P.x**3 + a*P.x + b)) % p == 0 and 0 <= P.x < p and 0 <= P.y < p


def inverse_point(P,p):
    O = 'Inf_Point'
    # Just calculates the inverse point
    if P == O:
        return P
    return Point(P.x, (-P.y) % p)


def point_add(P, Q, a, b, p):
    O = 'Inf_Point'
    # Checking that the points are valid if not raise an exception error
    if not (point_valid(P,a,b,p) and point_valid(Q,a,b,p)):
        raise ValueError("Invalid inputs")

    if P == O:
        R = Q
    elif Q == O:
        R = P
    elif Q == inverse_point(P,p):
        R = O
    else:
        if P == Q:
            try:
                inv = mod_inverse(2 * P.y,p)
            except ValueError:
                return 2 * P.y
            dydx = (3 * P.x**2 + a) * inv
        else:
            try:
                inv =  mod_inverse(Q.x - P.x,p)
            except ValueError:
                return Q.x - P.x
            dydx = (Q.y - P.y) * inv
        x = (dydx**2 - P.x - Q.x) % p
        y = (dydx * (P.x - x) - P.y) % p
        R = Point(x, y)

    # Making sure the result is on the curve
    assert point_valid(R,a,b,p)
    # Returning the result
    return R


def point_multiply(P,n,a,b,p):
    O = 'Inf_Point'
    Q = P
    R = O
    while n > 0:
        if n % 2 == 1:
            R = point_add(R,Q,a,b,p)
        Q = point_add(Q,Q,a,b,p)
        n = math.floor(n/2)
        if n > 0:
            continue
    return R



def random_curve(N):
    while True:
        A = secrets.randbelow(N)
        x = secrets.randbelow(N)
        y = secrets.randbelow(N)
        P = Point(x,y)
        B = (y**2 - x**3 - A*x) % N

        if (4*A**3 + 27*B**2) % N != 0:
            return (A,B,P)


def lenstra(N,B):
    a,b,P = random_curve(N)
    for i in range(2,B+1):
        if type(P)== int:
            d = math.gcd(P,N)
            if d < N:
                return d
            elif d == N:
                print('start again')
        Q = point_multiply(P,i,a,b,N)
        P = Q

print(lenstra(8453621,15))

大多数情况下,它会运行良好并返回一个整数除数;但是,有时会生成一条曲线,并出现以下错误:

Traceback (most recent call last):
  File "C:/Users/conta/PycharmProjects/Cryptography/Lenstras_Elliptic_Factor.py", line 99, in <module>
Point(x=6653683, y=2444813)
    print(lenstra(8453621,15))
Point(x=1943642, y=922559)
  File "C:/Users/conta/PycharmProjects/Cryptography/Lenstras_Elliptic_Factor.py", line 96, in lenstra
    Q = point_multiply(P,i,a,b,N)
  File "C:/Users/conta/PycharmProjects/Cryptography/Lenstras_Elliptic_Factor.py", line 65, in point_multiply
    R = point_add(R,Q,a,b,p)
  File "C:/Users/conta/PycharmProjects/Cryptography/Lenstras_Elliptic_Factor.py", line 27, in point_add
    if not (point_valid(P,a,b,p) and point_valid(Q,a,b,p)):
  File "C:/Users/conta/PycharmProjects/Cryptography/Lenstras_Elliptic_Factor.py", line 13, in point_valid
    return (P.y**2 - (P.x**3 + a*P.x + b)) % p == 0 and 0 <= P.x < p and 0 <= P.y < p
AttributeError: 'int' object has no attribute 'y'

您可以通过将参数设置为 a= 6518263 b=1551605 P = Point(x=6433033, y=7097171) 来重现此错误,而不是使用随机曲线。它失败了,因为当 P = 11 时,它不会打印并退出——它似乎尝试尝试以 11 作为参数调用 point_multiply 函数。我似乎无法阻止这种行为,我尝试了很多方法。

我发现如果我添加这个:

 if type(Q) == int:
    return Q

到函数 point_add() 的开头,然后它似乎按预期工作,尽管我觉得这不是理想的。

最佳答案

您没有检查 point_multiply 内两个 point_add 调用的结果以返回 如果返回的是 int 而不是 Point。

我将提出一些有点非正统的建议,这会冒犯一些编程纯粹主义者。 我认为当发现可能的因素时,您应该使用Exception来发出信号。 在我看来,这将使您的代码更加清晰和易于理解,并且因为找到一个 因素是一个“异常(exception)”条件,它不会损害性能。这是代码 使用 NotInvertibleError 用户定义异常的最小修改,并且它 还纠正了一两个错误。

import math
import secrets
from collections import namedtuple
import sympy

Point = namedtuple("Point", "x y")


class NotInvertibleError(Exception):
    def __init__(self, value):
        self.value = value


def mod_inverse(a, m):
    try:
        return sympy.mod_inverse(a, m)
    except ValueError:
        raise NotInvertibleError(a)


def point_valid(P, a, b, p):
    O = 'Inf_Point'
    if P == O:
        return True
    else:
        return (P.y ** 2 - (P.x ** 3 + a * P.x + b)) % p == 0 and 0 <= P.x < p and 0 <= P.y < p


def inverse_point(P, p):
    O = 'Inf_Point'
    # Just calculates the inverse point
    if P == O:
        return P
    return Point(P.x, (-P.y) % p)


def point_add(P, Q, a, b, p):
    O = 'Inf_Point'
    # Checking that the points are valid if not raise an exception error
    if not (point_valid(P, a, b, p) and point_valid(Q, a, b, p)):
        raise ValueError("Invalid inputs")

    if P == O:
        R = Q
    elif Q == O:
        R = P
    elif Q == inverse_point(P, p):
        R = O
    else:
        if P == Q:
            inv = mod_inverse(2 * P.y, p)
            dydx = (3 * P.x ** 2 + a) * inv
        else:
            inv = mod_inverse(Q.x - P.x, p)
            dydx = (Q.y - P.y) * inv
        x = (dydx ** 2 - P.x - Q.x) % p
        y = (dydx * (P.x - x) - P.y) % p
        R = Point(x, y)

    # Making sure the result is on the curve
    assert point_valid(R, a, b, p)
    # Returning the result
    return R


def point_multiply(P, n, a, b, p):
    O = 'Inf_Point'
    Q = P
    R = O
    while n > 0:
        if n % 2 == 1:
            R = point_add(R, Q, a, b, p)
        Q = point_add(Q, Q, a, b, p)
        n = math.floor(n / 2)
        if n > 0:
            continue
    return R


def random_curve(N):
    while True:
        A = secrets.randbelow(N)
        x = secrets.randbelow(N)
        y = secrets.randbelow(N)
        P = Point(x, y)
        B = (y ** 2 - x ** 3 - A * x) % N

        if (4 * A ** 3 + 27 * B ** 2) % N != 0:
            return (A, B, P)


def lenstra(N, B):
    while True:
        a, b, P = random_curve(N)
        try:
            for i in range(2, B + 1):
                Q = point_multiply(P, i, a, b, N)
                P = Q
        except NotInvertibleError as e:
            d = math.gcd(e.value, N)
            if d < N:
                return d
            elif d == N:
                print("start again")



while True:
    print(lenstra(8453621, 15))

我强烈反对使用异常来返回值, 但对于一些因式分解算法,包括 Lenstra 的 Elliptic 曲线因式分解异常条件,无法计算逆, 是触发该因素发现的原因,因此这是很自然的 使用一些附加信息传播异常。

关于python-3.x - Lenstras 椭圆曲线属性错误问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57579326/

相关文章:

python - 导致语法无效的 Unicode 文字

Python,在带有变量的列表中查找项目

python - Python中对数计算的底数会影响速度吗?

python - 生成给定文件夹的文件名列表

cryptography - 使用椭圆曲线密码术使用公钥加密并使用私钥解密

python - 从 RDS 检索数据给出 AttributeError : 'sqlalchemy.cimmutabledict.immutabledict' object has no attribute 'setdefault'

c# - 如何使用 RsaCng 作为 SignedXml 的 SigningKey?

java - "NoPadding"参数在 Cipher 类中到底有什么作用?

python - 收到错误 AttributeError : '_tkinter.tkapp' object has no attribute 'getitems'

python - opencv `cv2` python 模块中缺少 CAP_PROP_FRAME_COUNT 常量