计算机上的每个字母都对应一个独特的编号,普遍接受的标准是ASCII(美国信息交换标准代码)。例如,大写字母的A的ASCII码是65,星号(*)的ASCII码是42,而小写字母k的代码是107。

一种现代的加密方法是:输入一个文本文件,把其中的字节转化为对应的ASCII码,然后用从秘钥中获得的特定值和每个字节做异或运算。异或函数的一个好处是对密文使用同样的密钥就可以还原出明文,比如\(65\ XOR\ 42=107\),同时\(107\ XOR\ 42=65\)。

如果密钥的长度和明文的长度一样长并且密钥是完全随机的,那么这个加密就是不可破译的。用户会把加密后的信息和密钥放在不同的地方,如果不能同时获得两者,则不可能解密这条信息。

不幸的是,上述方法对于大部分用户来说是不实用的,所以通常会使用一种修正的方法,也就是用一个密码单词来作为密钥。如果这个密钥单词比想要加密的信息短(通常都是这样),那么这个密钥就会在整个信息中重复使用。一种折中的方案是:使用一个足够长的密码单词来保证安全,同时这个单词又不至于太长因此更好记住。

通过告诉你以下内容我们把你的任务变得简单了一些:已知密钥包含三个小写的英文字母,同时文本文件p059_cipher.txt包含了加密后的ASCII码,并且明文只包含普通的英文单词。现在请你解密这条信息并且找到原文对应的ASCII码的总和。

分析:这是一道密码学的题目,如果能对相关的密码学背景知识有一定的了解,这道题就会容易很多。如果大家感兴趣的话,可以看一看《码书 : 编码与解码的战争》这本书,这是一本相当精彩的密码学科普读物。作者西蒙·辛格是一位英国数学家,他同时也是《费马大定理 : 一个困惑了世间智者358年的谜》这本书的作者,这本书也相当精彩,能够把枯燥的数学知识写得如此生动有趣,扣人心弦的作者唯实不多。

言归正传,题目已经说了密钥由三个英文小写字母构成,考虑到三个小写字母最多只能构成\(26^3=17576\)种组合,所以这道题也可以用暴力破解的方式。用这一万多个密钥逐个去试,只到原文表现像正常的英文,那么这个密钥就是正确的,这时再把原文对应的ASCII码加总即为题目所求,但显然我们还有其它更好的办法。在《码书》一书中,作者讲述了一种古代非常流行的加密方法,也就是替代法,我们可以把原文的英文字母替换成其它不同的英文字母,比如我们可以把C替换成E,A替换成K,T替换成Z,这样CAT这个单词就变成了EKZ,这种替换映射关系也就是密钥,当信息的接收者收到密文,就可以用这个密钥反推出明文。这个方法大约是在古罗马时期发明的,在很长一段时间里是一种非常安全的加密方法,没有人能够破译,只到欧洲中世纪,阿拉伯学者发现了破解这种密码的方法,也就是频率分析法。在像英语中这种表音文字中,每个字母的使用频率都是相对固定的,比如在英语中,字母E的使用频率最高,约为12.7%;字母T的使用频率其次,约为9.35%;字母Z的使用频率最低,约为0.077%。因此只要我们收集足够多的密文,统计其中各个字母的出现频率,并把这种频率分布和英语的频率分布相对照,就不难猜出密文中的字母与原文中字母的对应关系,从而破解这种密码。

本题中涉及的异或加密法实际上和替代法非常类似,所以也可以用频率分析法破解。首先我们看一下异或加密法的工作原理,对于异或加密不太了解的同学,可以参见这篇维基。假设我现在有一段明文是"hello world!",我确定一个比明文长度要短的字母组合作为密码单词,比如说密码单词是"god",包含空格但不包含左右引号的原文长度为12,而密码单词长度为3,所以我们需求循环使用四次密码单词来对原文进行加密。首先我们对字母"h"和字母"g"对应的ASCII码进行异或运算,得到结果是15;然后对字母"e"和字母"o"对应的ASCII码进行异或运算,得到10。依次类推,字母"l"和字母"d"配对,下一个字母"l"和字母"g"配对进行异或运算,最终得到整个密文为[15,10,8,11,0,68,16,0,22,11,11,69]。假如我们要恢复原文,我们只需要对这个密文按照上面加密类似的方式用密码单词进行异或运算,如将15和字母"g"对应的ASCII码103进行异或运算得到104,其对应的英文字母正是"h"。

现在我们看看如何用频率分析法破解异或加密,首先题目已经告诉我们密码单词长度为三,因此我们知道原文的第一个和第四个字母是用密码单词的第一个字母加密的、第二个和第五个字母是用第二个字母、第三个和第六个字母是用第三个字母。之后依次类推。因此,我们可以将密文分为三组,每组密文都是使用同一个密码单词中的字母加密的。然后我们对每一组密文进行频率分析,找到出现频率最高的密文:第一组出现频率最高的密文是69,出现了86次;第二组频率最高的是88,出现了77次;第三组频率最高的是80,出现了103次。在一段正常的英文中,出现频率最高的一般是空格,所以我们猜测上面三个频率最高的密文对应的明文都是空格(正因为此,所以一般加密时都会把原文的空格去掉,否则就会太容易破解了,但是经过尝试我发现题目为了简化在加密时并没有去掉空格)。现在我们只需要把明文也就是空格对应的ASCII码和相应的密文进行异或运算就可以得到密钥了。空格对应的ASCII码是32,首先把32和69进行异或运算得到101,对应的英文字母是"e";然后把32和88进行异或运算得到120,对应的英文字母是"x";最后把80和32进行异或运算得到112,对应的英文字母是"p",因此我们得到密码单词是"exp"。我们可以用这个密码单词对密文进行解密,得到原文如下:

An extract taken from the introduction of one of Euler's most celebrated papers, "De summis serierum reciprocarum" [On the sums of series of reciprocals]: I have recently found, quite unexpectedly, an elegant expression for the entire sum of this series 1 + 1/4 + 1/9 + 1/16 + etc., which depends on the quadrature of the circle, so that if the true sum of this series is obtained, from it at once the quadrature of the circle follows. Namely, I have found that the sum of this series is a sixth part of the square of the perimeter of the circle whose diameter is 1; or by putting the sum of this series equal to s, it has the ratio sqrt(6) multiplied by s to 1 of the perimeter to the diameter. I will soon show that the sum of this series to be approximately 1.644934066842264364; and from multiplying this number by six, and then taking the square root, the number 3.141592653589793238 is indeed produced, which expresses the perimeter of a circle whose diameter is 1. Following again the same steps by which I had arrived at this sum, I have discovered that the sum of the series 1 + 1/16 + 1/81 + 1/256 + 1/625 + etc. also depends on the quadrature of the circle. Namely, the sum of this multiplied by 90 gives the biquadrate (fourth power) of the circumference of the perimeter of a circle whose diameter is 1. And by similar reasoning I have likewise been able to determine the sums of the subsequent series in which the exponents are even numbers.

有趣的是,这是欧拉的一篇著名论文中的段落,在这篇论文里他解决了著名的巴塞尔问题,即求出了以下无穷级数的和:

\[\sum_{k=1}^\infty \frac{1}{k^2}=1+\frac{1}{4}+\frac{1}{9}+\frac{1}{16}+\cdots=\frac{\pi^2}{6}
\]

这启发了黎曼进一步研究黎曼\(Zeta\)函数的性质,发现了黎曼\(Zeta\)函数的非平凡零点与质数分布规律之间的隐秘联系,在研究过程中产生的黎曼猜想至今仍是数学领域未被解决的重要猜想之一。更加有意思的是,显然欧拉工程的出题者暗中对这个题目的密钥和原文进行了修改,因为如果你在网络上搜索这道题目,你会发现以前解出这道题的人计算出来的密码单词是"god",而明文则是来自《圣经·约翰福音》第一章。显然,还是欧拉的论文更加符合欧拉工程这个网站的定位。

弄清楚了以上原理并知道密码单词之后,代码实现就相对比较简单了。用密码单词中的每个字母逐项与密文进行异或运算获得原文对应的ASCII码再求和,即为题目所求。代码如下:

# time cost = 668 µs ± 3.63 µs

from collections import Counter

def main():
with open('data/ep59.txt') as f:
cipher = list(map(int,f.read().split(',')))
space_ascii = ord(' ')
key = [Counter(cipher[i::3]).most_common(1)[0][0] ^ space_ascii for i in range(3)]
cycles = len(cipher)//3
res = sum([x^y for x,y in zip(cipher,key*cycles)])
return res

Project Euler 59: XOR decryption的更多相关文章

  1. Python练习题 039:Project Euler 011:网格中4个数字的最大乘积

    本题来自 Project Euler 第11题:https://projecteuler.net/problem=11 # Project Euler: Problem 10: Largest pro ...

  2. [project euler] program 4

    上一次接触 project euler 还是2011年的事情,做了前三道题,后来被第四题卡住了,前面几题的代码也没有保留下来. 今天试着暴力破解了一下,代码如下: (我大概是第 172,719 个解出 ...

  3. Python练习题 029:Project Euler 001:3和5的倍数

    开始做 Project Euler 的练习题.网站上总共有565题,真是个大题库啊! # Project Euler, Problem 1: Multiples of 3 and 5 # If we ...

  4. Project Euler 9

    题意:三个正整数a + b + c = 1000,a*a + b*b = c*c.求a*b*c. 解法:可以暴力枚举,但是也有数学方法. 首先,a,b,c中肯定有至少一个为偶数,否则和不可能为以上两个 ...

  5. Project Euler 44: Find the smallest pair of pentagonal numbers whose sum and difference is pentagonal.

    In Problem 42 we dealt with triangular problems, in Problem 44 of Project Euler we deal with pentago ...

  6. project euler 169

    project euler 169 题目链接:https://projecteuler.net/problem=169 参考题解:http://tieba.baidu.com/p/2738022069 ...

  7. 【Project Euler 8】Largest product in a series

    题目要求是: The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × ...

  8. Project Euler 第一题效率分析

    Project Euler: 欧拉计划是一系列挑战数学或者计算机编程问题,解决这些问题需要的不仅仅是数学功底. 启动这一项目的目的在于,为乐于探索的人提供一个钻研其他领域并且学习新知识的平台,将这一平 ...

  9. Python练习题 049:Project Euler 022:姓名分值

    本题来自 Project Euler 第22题:https://projecteuler.net/problem=22 ''' Project Euler: Problem 22: Names sco ...

随机推荐

  1. 不就是SELECT COUNT语句吗,竟然能被面试官虐的体无完肤

    数据库查询相信很多人都不陌生,所有经常有人调侃程序员就是CRUD专员,这所谓的CRUD指的就是数据库的增删改查. 在数据库的增删改查操作中,使用最频繁的就是查询操作.而在所有查询操作中,统计数量操作更 ...

  2. php分页的条件

    我们在项目开发的过程中避免不了使用分页功能,拿php来说,现在市面上有很多大大小小的php框架,当然了分页这种小功能这些框架中都是拿来直接可以用的. 这些框架的分页功能使用都很方便,配置一下分页所需参 ...

  3. Could not initialize class com.fasterxml.jackson.databind.SerializationConfig

    问题 Spring web 与 Spring eureka集成后出现错误: Caused by: java.lang.NoClassDefFoundError: Could not initializ ...

  4. 学习python3高阶函数笔记和demo

    python的高阶函数的定义是:一个函数接收另一个函数作为参数,这种函数就称之为高阶函数 举一个最简单的例子: def text(a,b,c): return c(a)+c(b) print( tex ...

  5. 百万年薪python之路 -- 带颜色的print

    带颜色的print print输出带颜色的方法详解 书写格式: 开头部分:\033[显示方式;前景色;背景色m + 结尾部分:\033[0m ​ 注意:开头部分的三个参数:显示方式,前景色,背景色是可 ...

  6. Django中ORM的优化

    1. exists( ) 什么时候用 count( ) 和 len( )什么时候合适, 用values( )或values_list( )只取需要的列的数据 iterator()对数据对象生成迭代器, ...

  7. Java基础(二十八)Java IO(5)RandomAccessFile类与过滤器流(Filter Stream)

    一.RandomAccessFile类 使用RandomAccessFile类可以读取任意位置数据的文件. 1.构造方法 RandomAccessFile(String name, String mo ...

  8. NetworkManager网络通讯_networkReader/Writer(六)

    unet客户端和服务端进行消息发送时可以采用上一节中方法,也可以直接用networkReader/Writer类进行发送 (一)服务端/客户端注册消息 ; m_Server.RegisterHandl ...

  9. django-URL之从URL中获取关键字(七)

    主要用于查询操作. 主要目录 book/views.py from django.http import HttpResponse from django.shortcuts import rende ...

  10. 【原创】怎样才能写出优雅的 Java 代码?这篇文章告诉你答案!

    本文已经收录自 JavaGuide (59k+ Star):[Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识. 本文比较简短,基本就是推荐一些对于写好代码非常有用的文章或者 ...