Tonelli-Shanks算法_python

Tonelli-Shanks算法_python

该算法应用于求二次剩余

也就是形如 x 2 ≡ n ( m o d p ) x^2\equiv n\pmod p x2n(modp)​的同余式,已知 n , p n,p n,p​求 x x x

判断二次(非)剩余

为了执行这个算法,需要知道如何判断二次(非)剩余

所谓二次(非)剩余也就是上面提到的同余式有无解的另一个说法

而判断二次剩余我们可以使用欧拉准则

n p − 1 2 ≡ 1 ( m o d p ) n^{\frac{p-1}{2}}\equiv 1\pmod p n2p11(modp)​;此情况为有解​

n p − 1 2 ≡ − 1 ( m o d p ) n^{\frac{p-1}{2}}\equiv -1\pmod p n2p11(modp)​​;此情况为无解

python表示为

if pow(n,(p-1)//2,p) == 1:
	print("二次剩余")
if pow(n,(p-1)//2,p) == p - 1:
	print("二次非剩余")

这里二次非剩余的判断条件不是 − 1 -1 1而是 p − 1 p-1 p1,是因为在pow()函数计算的结果不会为负数,那么在模 p p p的世界中 p − 1 p-1 p1等价于 − 1 -1 1

A l g o r i t h m   p r o c e s s Algorithm~process Algorithm process

同余式 x 2 ≡ n ( m o d p ) x^2\equiv n\pmod p x2n(modp);其中 p p p为奇素数

  • 首先确保 n n n p p p的二次剩余,有个性质可以简单地判断,就是 n n n​是否为平方数

  • 如果 p p p满足 p ≡ 3 ( m o d 4 ) p\equiv 3\pmod 4 p3(mod4),那么直接返回算法结果 r = n p + 1 4 ( m o d p ) r=n^{\frac{p+1}{4}}\pmod p r=n4p+1(modp)

  • q = p − 1 q=p-1 q=p1​​​,然后不断地让 p p p​除 2 2 2​,直到 p p p​成为一个奇数,整除的次数记作 s s s

  • 选择一个整数 z z z​使得 z z z​是 p p p​的二次非剩余,并计算 c ≡ z q ( m o d p ) c\equiv z^q\pmod p czq(modp)

  • r ≡ n q + 1 2 ( m o d p ) r\equiv n^{\frac{q+1}{2}}\pmod p rn2q+1(modp) t ≡ n q ( m o d p ) t\equiv n^q\pmod p tnq(modp) m = s m=s m=s

  • 进行外层循环

t t t满足 t ≡ 1 ( m o d p ) t\equiv 1\pmod p t1(modp),返回算法结果 r r r

  • 否则,进行内层循环

令中间值 t e m p ≡ t 2 i ( m o d p ) temp\equiv t^{2^{i}}\pmod p tempt2i(modp),当 t e m p temp temp​满足 t e m p ≡ 1 ( m o d p ) temp\equiv 1\pmod p temp1(modp)时进行以下计算

b ≡ c 2 m − i − 1 ( m o d p ) b\equiv c^{2^{m-i-1}}\pmod p bc2mi1(modp)​;注意,这里的 i i i​也就是 t e m p ≡ t 2 i ( m o d p ) temp\equiv t^{2^i}\pmod p tempt2i(modp)​的 i i i

r ≡ r ∗ b ( m o d p ) r\equiv r*b\pmod p rrb(modp)

c ≡ b ∗ b ( m o d p ) c \equiv b*b\pmod p cbb(modp)

t ≡ t ∗ c ( m o d p ) t\equiv t*c\pmod p ttc(modp)​;这里重新赋值了 t t t,也就是外层循环的 t t t,若满足外层循环的条件则返回算法结果,若不满足则继续内层循环

m = i m=i m=i


到这里算法就结束了,返回结果 r r r即是二次剩余的解

P y t h o n   a p p l i c a t i o n Python~application Python application

def Legendre(n,p): # 这里用勒让德符号来表示判断二次(非)剩余的过程
    return pow(n,(p - 1) // 2,p)
def Tonelli_Shanks(n,p):
    assert Legendre(n,p) == 1
    if p % 4 == 3:
        return pow(n,(p + 1) // 4,p)
    q = p - 1
    s = 0
    while q % 2 == 0:
        q = q // 2
        s += 1
    for z in range(2,p):
        if Legendre(z,p) == p - 1:
            c = pow(z,q,p)
            break
    r = pow(n,(q + 1) // 2,p)
    t = pow(n,q,p)
    m = s
    if t % p == 1:
        return r
    else:
        i = 0
        while t % p != 1: # 外层循环的判断条件
            temp = pow(t,2**(i+1),p) # 这里写作i+1是为了确保之后内层循环用到i值是与这里的i+1的值是相等的
            i += 1
            if temp % p == 1: # 内层循环的判断条件
                b = pow(c,2**(m - i - 1),p)
                r = r * b % p
                c = b * b % p
                t = t * c % p
                m = i
                i = 0 # 注意每次内层循环结束后i值要更新为0
        return r

C a l l   m o d u l e Call~module Call module

sympy模块内有封装好了的函数可以计算二次剩余

nthroot_mod()用于求解于 n i n d e x ≡ x ( m o d p ) n^{index}\equiv x\pmod p nindexx(modp)的同余式

from sympy.ntheory.residue_ntheory import nthroot_mod
x=nthroot_mod(n,index,p)

E x a m p l e Example Example

V&N2020的一道Crypto:Easy RSA

题目算到最后已知 m 2 ≡ c ( m o d r ) m^2\equiv c\pmod r m2c(modr),已知 c , r c,r c,r m m m

直接代入定义好了的Tonelli_Shanks()函数即可

代码实现

from Crypto.Util.number import *

c = 8081092455112516397361105816900490085355315574087538340788309885334106796325593823678787887569920404814986643819898763828872716522338864714182757065213683
r = 10269028767754306217563721664976261924407940883784193817786660413744866184645984238866463711873380072803747092361041245422348883639933712733051005791543841
def Legendre(n,p):
    return pow(n,(p - 1) // 2,p)
def Tonelli_Shanks(n,p):
    assert Legendre(n,p) == 1
    if p % 4 == 3:
        return pow(n,(p + 1) // 4,p)
    q = p - 1
    s = 0
    while q % 2 == 0:
        q = q // 2
        s += 1
    for z in range(2,p):
        if Legendre(z,p) == p - 1:
            c = pow(z,q,p)
            break
    r = pow(n,(q + 1) // 2,p)
    t = pow(n,q,p)
    m = s
    if t % p == 1:
        return r
    else:
        i = 0
        while t % p != 1:
            temp = pow(t,2**(i+1),p)
            i += 1
            if temp % p == 1:
                b = pow(c,2**(m - i - 1),p)
                r = r * b % p
                c = b * b % p
                t = t * c % p
                m = i
                i = 0
        return r
    
result = Tonelli_Shanks(c,r)
print(result)
print(long_to_bytes(result))

p e f e r e n c e peference peference

Tonelli-Shanks algorithm - Rosetta Code

(11条消息) BUUCTF Crypto V&N2020 公开赛]easy_RSA wp_hsqGOD’s blog-CSDN博客

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
很抱歉,由于缺少 `secret.py` 文件,我无法运行这段代码。但是,根据代码逻辑和命名,可以猜测这是一个 RSA 相关的加密程序,其中使用了 Pell 方程和 TonelliShanks 算法来实现 RSA 的快速解密。具体来说,代码中的 `keygen()` 函数生成了两个大质数 $p$ 和 $q$,然后计算 $n=pq$。接下来,通过求解 Pell 方程 $x^2-Dy^2=1$ 找到一个解 $(x,y)$,其中 $D=1117$。然后,使用 TonelliShanks 算法分解 $n$,得到 $p$ 和 $q$。接着,计算 $u_1$ 和 $u_2$,然后使用 CRT 计算 $v=u_1qq^{-1} + u_2pp^{-1}$。最后,将明文分成两个部分,分别使用 RSA 加密,并输出密文。 具体的解密过程如下: 设密文为 $(c_1,c_2)$,其中 $c_1$ 和 $c_2$ 分别是原始明文的两个部分的 RSA 加密结果。根据 RSA 加密的公式,有: $$ c_1 \equiv m_1^{e_1} \pmod{p} \\ c_1 \equiv m_1^{e_1} \pmod{q} \\ c_2 \equiv m_2^{e_2} \pmod{p} \\ c_2 \equiv m_2^{e_2} \pmod{q} $$ 其中,$e_1$ 和 $e_2$ 分别是 $p$ 和 $q$ 的 RSA 加密指数。由于 $p$ 和 $q$ 都是奇素数,因此有 $p-1=2^{s_p}t_p$ 和 $q-1=2^{s_q}t_q$,其中 $t_p$ 和 $t_q$ 都是奇数。根据 TonelliShanks 算法,可以计算出 $m_2^{(p+1)/4}$ 和 $m_2^{(q+1)/4}$ 的平方根 $r_p$ 和 $r_q$,使得 $r_p^2 \equiv m_2^{(p+1)/4} \pmod{p}$,$r_q^2 \equiv m_2^{(q+1)/4} \pmod{q}$,然后使用 CRT 合并 $r_p$ 和 $r_q$ 得到 $r$,即: $$ r = (r_p q q^{-1} + r_q p p^{-1}) \pmod{n} $$ 然后,对于 $m_1$,可以使用扩展欧几里得算法求出 $p$ 的乘法逆元 $d_p$,使得 $d_p p \equiv 1 \pmod{t_p}$,然后计算 $m_1^{e_1} \equiv c_1^{d_p} \pmod{p}$。同理,对于 $m_2$,可以使用扩展欧几里得算法求出 $q$ 的乘法逆元 $d_q$,使得 $d_q q \equiv 1 \pmod{t_q}$,然后计算 $m_2^{e_2} \equiv c_2^{d_q} \pmod{q}$。最后,将 $m_1$ 和 $r$ 合并得到原始明文,即 $m=m_1 + r$。 根据以上步骤,可以编写以下代码实现解密过程:
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

M3ng@L

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值