22saf

20211201李柏林發表於2024-06-17
def partial_p(p0, kbits, n):
    # Ensure n is an integer (as it should be), and create the polynomial ring over Z/nZ
    PR.<x> = PolynomialRing(Zmod(n))
    nbits = n.nbits()  # Get the number of bits in n
    f = Integer(2)^kbits * x + Integer(p0)  # Ensure all numbers are integers
    f = f.monic()  # Make the polynomial monic

    # Find small roots of the polynomial
    try:
        roots = f.small_roots(X=Integer(2)**(nbits // 2 - kbits), beta=RealNumber('0.3'))
    except Exception as e:
        print(f"Error in small_roots: {e}")
        return None
    
    if roots:
        x0 = Integer(roots[0])  # Get the first root and ensure it's an integer
        p = gcd(Integer(2)^kbits * x0 + p0, n)  # Compute gcd to find p
        return ZZ(p)  # Return p as an integer
    return None

def find_p(d0, kbits, e, n):
    X = var('X')  # Define a symbolic variable X

    # Iterate through possible values of k
    for k in range(1, e + 1):
        # Solve the modular equation for possible values of p0
        results = solve_mod([e * d0 * X - k * X * (n - X + 1) + k * n == X], 2^kbits)
        for x in results:
            p0 = ZZ(x[0])  # Convert the solution to an integer
            p = partial_p(p0, kbits, n)  # Try to find p using partial_p
            if p:
                return p  # Return p if found
    return None

if __name__ == '__main__':
    n = 0xcc5b706f373a79c680cec9527aac573fd435129cf16c23334085bf97832e5a6c78b633c2f244b12a62f87ec5295dd89fcf3c808c39e45a9afdbda2f8d2d0b50d61b685c0fe9eb41a7018a40f98892f96d738e2a4e740d4e507bcbd07f68c1ecb2ca10bd780ce65265a7e4da00f1031a5db9d038878a29a5ffefcaf2119720005
    e = 65537
    d0 = 0x20142ae2802b877eb4dfa8a462e7d017c4d348181c367fd1a661ec9b6bbcca9dcb6601ccb6c10416b7f3c20129527346bbc136ee60f9945125cba03a9bba3720f7411
    
    nbits = n.nbits()  # Get the number of bits in n
    print(f"nbits: {nbits}")

    kbits = d0.nbits()  # Number of bits in the given part of d
    print(f"kbits: {kbits}")
    
    print(f"lower {kbits} bits (of {nbits} bits) are given")
    
    # Attempt to find p
    p = find_p(d0, kbits, e, n)
    if p:
        print(f"Found p: {p}")
        q = n // p  # Compute q
        print(f"Found q: {q}")
        private_exponent = inverse_mod(e, (p - 1) * (q - 1))  # Compute the private exponent
        print(f"Private exponent: {private_exponent}")
    else:
        print("Failed to find p.")