首页
社区
课程
招聘
[原创] CodinGame最高难度Nintendo挑战题
发表于: 1小时前 49

[原创] CodinGame最高难度Nintendo挑战题

1小时前
49

几年前在CodinGame上遇到过一道没解出的题。最近再看到,思路阔然开朗,感慨颇多。


题目是一段简单代码,核心只有一行表达式(原题见附件):

输出 array b 为:

要求反推输出 array a



一直觉得相关专业的教材,行文逻辑对新人极不友好。比如抽象代理中介绍RSA原理,开篇就是:


给定两个大素数 p 和 q


这不是在解释密码学原理,只是凭空给到的实现工序。如果诚心教学,应该从设计初衷讲起:


message encrypt = cipher

cipher decrypt = message


有了最简PoC之后 => 再披露安全缺陷 => 然后才有动机引入欧拉函数,而不是颠倒过来讲。至于AI,在稍复杂数学问题上的解释能力,更是惨不忍睹。


我无法去改变行业现状,只能轮到自己写writes up的时候,更用心些。



i j 双循环即是二维平面,每个格子代表了第i列、第j行,直观来看代码逻辑就是在遍历棋盘。


不难看出,a[i/32] >> (i%32) 中的 i/32  代表了入参的第几个block、 i%32 代表了第几个block下的偏移量,合在一起就是在取整体入参序列的第 i 位(j同理)。


... & ... & 1 可以理解为取行、列值同时为1的格。


b[(i+j)/32] ^= ... << ((i+j)%32) ,可以理解为上述格在斜线上的求和(因为同一斜线中每个格子的 i+j 恒定)。


至此,我们对这段代码的几何意义有了直觉理解。接下来要做的就是配平这枚魔方。



几何理解只是一个锚点,他帮助我们产生进一步联想。看到这个纺锤状的图形,很容易回忆起小学时的乘法竖式。


我们列出 x3x2x1x0 * y3y2y1y0 的竖式,体会下


不难发现:末行的表达式恰好贴合本题的代码逻辑(只不过这里的加法需要重定义为不进位加法,即:异或)。



那么,这份代码本质上在做以下事情:


输出B = 输入A的前半段 x 输入A的后半段


至此,课题退化为已知公案:大数因数分解“易题”(与RSA的自然数分解不同,由于这里乘法不带进位,应属于伽罗瓦域运算)



从这里开始,解题思路走到了一个关键的岔路口,摆在面前有两个方向。


我认为本手就应该继续配平魔方,机制很明确:

每拨动1位横坐标+1位纵坐标,会产生1个新增黑点,同时产生若干灰点(余数)。

多个余数组合,又恰好产生新的黑点。

核心命题是如何在这套体系下,归纳出能独立扰动单格输出槽位的公式。这是人类最能直观理解的方向。


另外一种取巧的方向,是直接复用整数环上的因数分解攻击方案,在本题的语境下做合理外推。

套用既有公式得到端到端的答案,代价是丢失对计算过程的直觉理解。


碍于精力有限,我暂时选了方向 2。


但我们很难评判,鸡兔同笼的巧思,被解方程这种工具彻底取代后,到底是人类思想的进步还是退化。

我粗浅的理解是,数学只是人类对世界规律的有损压损,不是世界本身。如果不回归到生活经验,最终会走向歧途。




因数分解问题主要有三个攻击方案(不考虑Shor算法)

Pollard Rho(差速指针)

二次筛法

数域筛法

理论上RSA的攻击方案,在重载操作符后,对本题都应该适用。


我最先尝试了 Pollard Rho,由于算法本身存在概率缺陷,解不了本题。

紧接着尝试二次筛法。在伽罗瓦域上确实存在一个与二次筛法思路接近的方案,即:Berlekamp算法。


让我们从零开始反推下Berlekamp算法的设计思路。



把 B 分解为 A1 * A2


如果我们想要地毯式搜寻 A1 * A2 这株独苗,命中概率显然小得可怜。有没有可能放宽条件呢?

        可以尝试先找到A1的一个倍数,与B辗转相除求最大公约数,这样也能得出A1(平凡因子除外)

如此,问题从找A1,转变为找n倍的A1,靶面立刻被放大了无数倍。


这类倍数思想在素数领域很常见,所以最先容易联想到。比如最简单的判断素数方法,就是在自然数序列中,把2的倍数、3的倍数、4的倍数依次拉黑,那么剩余没人认领的数就是素数。



冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

最后于 1小时前 被逆向大聪明编辑 ,原因:
上传的附件:
收藏
点赞 ・0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回