---
# System prepended metadata

title: Quiz 3

---

# 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 的公私鑰是不變的，所以不能稱為完美密碼。