二次剩余的通解

我们通常所说的二次剩余一般是指p%4==3,然而对于p我们还有很多情况 例如p%4==1,这样的话,解法会有所不同。

下面给出两个经典解法的脚本

from random import *


def legendre(a, p):
    symbol = pow(a, (p - 1) // 2, p)
    if symbol == p - 1:
        return -1
    return symbol


def tonelli(a, p):                      #Tonelli
    if a == 0 or legendre(a, p) != 1:
        return 0
    q = p - 1
    s = 0
    while q % 2 == 0:
        q //= 2
        s += 1
    if s == 1:
        return pow(a, (p + 1) // 4, p)

    z = 2
    while legendre(z, p) != -1:
        z += 1

    m = s
    c = pow(z, q, p)
    t = pow(a, q, p)
    r = pow(a, (q + 1) // 2, p)

    while t != 1:
        t2 = t
        i = 0
        while t2 != 1 and i < m:
            t2 = pow(t2, 2, p)
            i += 1
        b = pow(c, 2 ** (m - i - 1), p)
        m = i
        c = (b * b) % p
        t = (t * c) % p
        r = (r * b) % p

    return r


#x^2=c mod p
def Cipolla_algorithm(c,p):                         #Cipolla
    # 定义模p复数域上的乘法
    def multiplication(x1,y1,x2,y2,w,p):
        x=(x1*x2+y1*y2*w)%p
        y=(x1*y2+x2*y1)%p
        return x,y

    # 获取w,使得w=-1mod(p),w是复数元的平方
    def get_w(c,p):
        a=randint(1,p)
        w=pow(a, 2) - c
        while pow(w,(p - 1)//2,p)!=p-1:
            a=randint(1,p)
            w=pow(a,2)-c
        return w,a
    #主体部分
    w,a=get_w(c,p)
    power=(p+1)//2
    x1=a
    y1=1
    x=1
    y=0

    while(power!=0):
        if(power!=(p+1)//2):
            x1,y1=multiplication(x1,y1,x1,y1,w,p)
        if(power & 1):
            x,y=multiplication(x,y,x1,y1,w,p)
        power>>=1
    return x


print(tonelli(4,13))

print(Cipolla_algorithm(4,13))

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值