n为质数的二次剩余问题

前言

在做V&N 2020公开赛中的一道名叫easy_RSA的题目的时候遇到了这个问题
题目最后一步如下:

n = 10269028767754306217563721664976261924407940883784193817786660413744866184645984238866463711873380072803747092361041245422348883639933712733051005791543841 e = 2 c = 8081092455112516397361105816900490085355315574087538340788309885334106796325593823678787887569920404814986643819898763828872716522338864714182757065213683 # 求 m

我以为是Rabin问题,但模数为质数,并且不满足 n mod 4 == 3 ... 于是就卡住了(若模数不为质数,则可以考虑中国剩余定理,若n mod 4 == 3 ,则为rabin问题)

解法一、调用sympy中的nthroot_mod函数

from sympy.ntheory.residue_ntheory import nthroot_mod from Crypto.Util.number import long_to_bytes n = 10269028767754306217563721664976261924407940883784193817786660413744866184645984238866463711873380072803747092361041245422348883639933712733051005791543841 e = 2 c = 8081092455112516397361105816900490085355315574087538340788309885334106796325593823678787887569920404814986643819898763828872716522338864714182757065213683 m = nthroot_mod(c,2,n) print(long_to_bytes(m))

没有找到关于这个函数的介绍,就算是在官方文档里,也只是简单的提了一句:
Find the solutions to x**n = a mod p

解法二、Tonelli-Shanks算法

没有搞懂算法原理,直接贴代码了

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

参考
https://blog.csdn.net/qq_38200023/article/details/79534574?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~Rate-1-79534574-blog-49862189.pc_relevant_multi_platform_whitelistv3&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~Rate-1-79534574-blog-49862189.pc_relevant_multi_platform_whitelistv3&utm_relevant_index=1

https://en.wikipedia.org/wiki/Tonelli–Shanks_algorithm

exp:

from sympy.ntheory.residue_ntheory import nthroot_mod from Crypto.Util.number import long_to_bytes n = 10269028767754306217563721664976261924407940883784193817786660413744866184645984238866463711873380072803747092361041245422348883639933712733051005791543841 e = 2 c = 8081092455112516397361105816900490085355315574087538340788309885334106796325593823678787887569920404814986643819898763828872716522338864714182757065213683 # m = nthroot_mod(c,2,n) 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 m = Tonelli_Shanks(c,n) print(long_to_bytes(m)) ''' b'flag{fd462593-25e4-4631-a96a-0cd5c72b2d1b}' '''

__EOF__

本文作者_TLSN
本文链接https://www.cnblogs.com/lordtianqiyi/articles/17069468.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   TLSN  阅读(90)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示