# Quiz 3
## Program Description
### Part 1 - Calculating IC
1. By iterating through all the possible IC, calculate the IC of the current keylength for the groups.
```python=
for i in range(4, 8, 1):
# Constructing the groups for the keylength
grouping = []
for j in range(i):
grouping.append([])
# Put them into groups by their index
for j in range(len(text)):
grouping[j % i].append(text[j])
ic = np.zeros(i)
sum = np.zeros(i)
# For each group, calculate the IC and the total number of alphebets in the group
for j in range(i):
cipher = Counter(grouping[j])
ic2 = 0
sum2 = 0
for k in cipher.most_common():
ic[j] += k[1] * (k[1] - 1)
sum[j] += k[1]
# After the iteration, calculate the sum value of the IC group
ic[j] = ic[j] / (sum[j] * (sum[j] - 1))
# The value would be the average
if maxIC < np.average(ic):
maxIC = np.average(ic)
keyLength = i
```
2. For each group, we need to calculate the possible decryption key. By trying all the combinations, decrypt it using the one tried and calculate the appearance distance with the mornal plaintext. Finally obtain the smallest difference
```python=
# Construct the dcryption for all the group
decipherKey = ""
grouping = []
for j in range(keyLength):
grouping.append([])
for j in range(len(text)):
grouping[j % keyLength].append(text[j])
# For each group, go through all possibilities and try to decipher using the target
for j in range(keyLength):
cipher = Counter(grouping[j])
ic = np.zeros(26)
# Iterate through combination
for k in range(26):
for idx, val in cipher.most_common():
# Get the decipher value
decipher = ord(idx) - 65 - k
if decipher < 0:
decipher += 26
# Calculate the distance between the appearance of real plaintext and the target
ic[k] += pow(val - apperance[decipher], 2) / (apperance[decipher])
# Get the smallest one among IC
for idx, val in enumerate(ic):
if val == min(ic):
decipherKey += chr(idx + 65)
```
3. By turning it into plaintext, use the decrypt key
```python=
plain = ""
for j in range(len(text)):
# Use modulus to get the key for that index
decipher = ord(text[j]) - ord(decipherKey[j % keyLength])
if decipher < 0:
decipher += 26
# Restore is back using the key
plain += chr(decipher + 65)
print(plain)
```
## Bonus 2
不是,因為完美密碼每送一次都必須更換密鑰(也就是所謂的亂數)但是RSA 的公私鑰是不變的,所以不能稱為完美密碼。