我目前正在尝试解决此计划programing puzzle。难题是使用以下C ++代码加密消息:
int main()
{
int size;
cin >> size;
unsigned int* a = new unsigned int[size / 16]; // <- input tab to encrypt
unsigned int* b = new unsigned int[size / 16]; // <- output tab
for (int i = 0; i < size / 16; i++) { // Read size / 16 integers to a
cin >> hex >> a[i];
}
for (int i = 0; i < size / 16; i++) { // Write size / 16 zeros to b
b[i] = 0;
}
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++) {
b[(i + j) / 32] ^= ( (a[i / 32] >> (i % 32)) &
(a[j / 32 + size / 32] >> (j % 32)) & 1 ) << ((i + j) % 32); // Magic centaurian operation
}
for(int i = 0; i < size / 16; i++) {
if (i > 0) {
cout << ' ';
}
cout << setfill('0') << setw(8) << hex << b[i]; // print result
}
cout << endl;
/*
Good luck humans
*/
return 0;
}
目标是反转这种编码(在识别时应该是已知的数学运算)。我面临的问题是我无法理解编码的作用以及所有这些二进制操作正在做什么。你能解释一下这种编码是如何工作的吗?
谢谢!
答案 0 :(得分:2)
要了解操作是什么,请逐个循环逐行分解,然后应用优先级规则。没有更多,没有更少。如果我没有在按位沼泽中的任何地方丢失轨迹,其影响将归结为exclusive XOR
在b[(i + j) / 32]
处的原始值power of 2
范围内的0
有符号整数(或for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++) {
b[(i + j) / 32] ^=
( (a[i / 32] >> (i % 32)) &
(a[j / 32 + size / 32] >>
(j % 32)) & 1 ) <<
((i + j) % 32); // Magic centaurian operation
}
}
)。分析看起来像这样:
b[(i + j) / 32] ^=
第一项操作是什么:
exclusive OR
这是该索引值的idx
。如果你只是让b[idx] ^= stuff
代表计算索引的混乱,你可以把它写成:
right-to-left
应用优先规则(^=
为b[idx] = b[idx] ^ stuff
)的与写作相同:
stuff
优先顺序告诉我们,在将b[idx]
应用于stuff
之前,我需要弄清楚 | A | << | B |
| C | & | D | | |
| | | E | & 1 | | |
+-----------------+---+-----------------------+-----+----+-------------+
( (a[i/32]>>(i%32)) & (a[j/32+size/32]>>(j%32)) & 1 ) << ( (i+j) % 32 );
。看A << B
你有:
( C & D ) << B
向下突破,你有(C & E & 1) << B
,可以进一步细分为:
(C & E & 1) << B
或最后:
left-to-right
与B
相关的优先级规则全部应用(C & E & 1)
,以满足括号分组的要求。
那么i
是什么?这只是一个数字,分组j
将向左移动。就用整数中的位数修改的索引值(C & E & 1)
和0-31
而言,它只是将i+j
分组中的位向左移位(C & E & 1)
位取决于a[i/32]>>(i%32)
的组合值。
分组a[i/32]
是一个完全相似的分析。 (i%32)
只是E
向(a[j/32+size/32]>>(j%32))
向右移动的值(j%32)
。 ANDED
与略微不同的索引操作相同:1
这只是该索引右移(C & E & 1)
的值。这两个班次的结果都是C & E
和odd
。这意味着,如果两个odd
都是odd
个数值,整个分组1
将只有一个值。
为什么只有5 & 7 & 1
值?从二进制角度来看,101 & 111 & 1
个数字是唯一具有一位1
的值。 (例如even
(0
)= 0
)。如果任何值为(C & E & 1)
或A
,则整个分组将为A << B
。
了解分组A
(或我们主要归类为0
的内容),您现在可以查看:
1
知道A
将是1
或1
,您知道如果B
为B
,则转变结果具有价值的唯一方式,然后该组的结果将是0-31
左移A << B
位的值。知道0 - 2147483648
的范围为0 - 31
,A << B
的值范围介于0 - 2147483648
,但之间,因为您在0
之间移动{ {1}} 1
的值仅为10
(二进制:100
,1000
,b[idx] = b[idx] ^ stuff
,{{之间的2的正幂1}},exclusively OR
等等......)
然后最终将我们带到
110101
当你以{2}的幂为1000
任何东西时,你只能在该数字的 2的幂处翻转该位。 (例如111101
(26)^ b[idx] = b[idx] ^ stuff
(8)= b[idx] = b[idx] ^ (power of two)
(61))。所有其他位都保持不变。因此,所有操作的最终效果是:
b[idx] = b[idx] ^ 0 /* which is nothing more than b[idx] to begin with */
只不过:
end()
或
v[9] = 0;
如果您有任何疑问,请与我们联系。您可以轻松转储索引计算以查看值,但这应涵盖相关操作。
答案 1 :(得分:0)
此代码段在数组的前半部分(a[0:size/32]
)和数组的后半部分(a[size/32:size/16]
执行无进位乘法运算 )。
我在原始版本下面写了一个等价的二进制版本,希望这对你有帮助。
#include <iostream>
#include <iomanip>
#include <ios>
using namespace std;
int main() {
int size;
cin >> size;
unsigned int* a = new unsigned int[size / 16]; // <- input tab to encrypt
unsigned int* b = new unsigned int[size / 16]; // <- output tab
bool *a1 = new bool[size];
bool *a2 = new bool[size];
bool *bb = new bool[size * 2];
for (int i = 0; i < size / 16; i++) { // Read size / 16 integers to a
cin >> hex >> a[i];
}
for (int i = 0; i < size * 2; i++) {
if (i < size) {
a1[i] = (a[i / 32] & (1 << (i % 32))) > 0; // first `size` bits are for a1
} else {
a2[i - size] = (a[i / 32] & (1 << (i % 32))) > 0; // rest `size` bits are for a2
}
}
for (int i = 0; i < size / 16; i++) { // Write size / 16 zeros to b
b[i] = 0;
}
for (int i = 0; i < size * 2; i++) {
bb[i] = 0;
}
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++) {
b[(i + j) / 32] ^= ( (a[i / 32] >> (i % 32)) &
(a[j / 32 + size / 32] >> (j % 32)) & 1 ) << ((i + j) % 32); // Magic centaurian operation
}
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++) {
bb[i + j] ^= (a1[i] & a2[j] & 1); // some operation as multiply (*) do
}
for(int i = 0; i < size / 16; i++) {
if (i > 0) {
cout << ' ';
}
cout << setfill('0') << setw(8) << hex << b[i]; // print result
}
cout << endl;
for(int i = 0; i < size / 32 * 2; i++) {
if (i > 0) {
cout << ' ';
}
unsigned int hex_number = 0;
for (int j = 0; j < 32; j++) hex_number += bb[i * 32 + j] << j;
cout << setfill('0') << setw(8) << hex << hex_number; // print result
}
cout << endl;
return 0;
}