Rating:
## Hyper Normal
### Challenge
> Being normal is hard these days because of Corona virus pandemic!
```python
#!/usr/bin/env python3
import random
from flag import FLAG
p = 8443
def transpose(x):
result = [[x[j][i] for j in range(len(x))] for i in range(len(x[0]))]
return result
def vsum(u, v):
assert len(u) == len(v)
l, w = len(u), []
for i in range(l):
w += [(u[i] + v[i]) % p]
return w
def sprod(a, u):
w = []
for i in range(len(u)):
w += [a*u[i] % p]
return w
def encrypt(msg):
l = len(msg)
hyper = [ord(m)*(i+1) for (m, i) in zip(list(msg), range(l))]
V, W = [], []
for i in range(l):
v = [0]*i + [hyper[i]] + [0]*(l - i - 1)
V.append(v)
random.shuffle(V)
for _ in range(l):
R, v = [random.randint(0, 126) for _ in range(l)], [0]*l
for j in range(l):
v = vsum(v, sprod(R[j], V[j]))
W.append(v)
random.shuffle(transpose(W))
return W
enc = encrypt(FLAG)
print(enc)
```
### Solution
This challenge gives a strange encryption scheme. This encryption algorithm actually does this. For an input of length $l$, the algorithm first multiplies each character of the input by the corresponding index to obtain a vector $x$. Then the algorithm loops $l$ times, each time outputs a vector $v$. Each number in the vector $v$ is a random number between 0 and 126 multiplied by the corresponding number in the vector $x$. All these operations are performed modulo 8443.
It is worth noting that `random.shuffle` on line 38 of the program actually has no effect on the output, because the `transpose` function returns a new object.
Solving for the input is intuitive. For the i-th byte of the input, we simply iterate through all printable characters, multiply $i$ by those characters, and multiply 0 through 126 to get all possible results. If column $i$ of the program output happens to be a subset of the possible results generated by a character $c$, then the i-th byte of the input is likely to be $c$.
```python
#!/usr/bin/env python3
from string import printable
p = 8443
with open('output.txt', 'r') as f:
enc = eval(f.read())
results = []
for i in range(len(enc[0])):
tmp = []
for j in enc:
tmp.append(j[i])
results.append(tmp)
flag = ''
for idx, result in enumerate(results):
for c in printable:
possibilities = [ord(c)*i*(idx+1) % p for i in range(127)]
if all([i in possibilities for i in result]):
flag += c
break
print(flag)
```
##### Flag
`CCTF{H0w_f1Nd_th3_4lL_3I9EnV4Lu35_iN_FiN173_Fi3lD5!???}`