Jack698 commited on
Commit
5d057f3
·
verified ·
1 Parent(s): 31b9fe1

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. Dockerfile +19 -0
  2. README.md +23 -24
  3. main.py +118 -0
Dockerfile ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 使用官方 Python 运行时作为父镜像
2
+ FROM python:3.9-slim
3
+
4
+ # 先更新包列表,然后安装 git。
5
+ # --no-install-recommends 可以减少不必要的包安装,保持镜像体积较小。
6
+ # 最后清理 apt 缓存,这是减小镜像大小的好习惯。
7
+ RUN apt-get update && \
8
+ apt-get install -y git --no-install-recommends && \
9
+ rm -rf /var/lib/apt/lists/*
10
+
11
+ # 设置工作目录
12
+ WORKDIR /app
13
+ COPY . .
14
+
15
+ RUN pip install --no-cache-dir -r requirements.txt
16
+
17
+
18
+ # 容器启动时运行 main.py
19
+ CMD ["python", "main.py"]
README.md CHANGED
@@ -1,24 +1,23 @@
1
- ---
2
- title: Simple Substitution Cipher Decryptor
3
- emoji: 🕵️
4
- colorFrom: blue
5
- colorTo: green
6
- sdk: gradio
7
- app_file: app.py
8
- pinned: false
9
-
10
- ---
11
-
12
- # Simple Substitution Cipher Decryptor
13
-
14
- This is a simple tool to automatically decrypt text that has been encrypted with a simple substitution cipher.
15
-
16
- **How it works:**
17
- The backend uses n-gram frequency analysis (specifically quadgrams) to score possible decryptions and find the most likely plaintext.
18
-
19
- **How to use:**
20
- 1. Paste your ciphertext into the "Ciphertext" box.
21
- 2. (Optional) If you know any letter mappings (e.g., you know 'a' in the ciphertext is 'T' in the plaintext), you can provide them in the "Known Key Mappings" box. The format is `a=T b=E`.
22
- 3. The decrypted plaintext will appear in the "Plaintext" box.
23
-
24
- *Note: The decryption process is heuristic and may not always produce a perfect result, especially for short ciphertexts.*
 
1
+ ---
2
+ title: Simple Substitution Cipher Decryptor
3
+ emoji: 🕵️
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: gradio
7
+ app_file: main.py
8
+ pinned: false
9
+ ---
10
+
11
+ # Simple Substitution Cipher Decryptor
12
+
13
+ This is a simple tool to automatically decrypt text that has been encrypted with a simple substitution cipher.
14
+
15
+ **How it works:**
16
+ The backend uses n-gram frequency analysis (specifically quadgrams) to score possible decryptions and find the most likely plaintext.
17
+
18
+ **How to use:**
19
+ 1. Paste your ciphertext into the "Ciphertext" box.
20
+ 2. (Optional) If you know any letter mappings (e.g., you know 'a' in the ciphertext is 'T' in the plaintext), you can provide them in the "Known Key Mappings" box. The format is `a=T b=E`.
21
+ 3. The decrypted plaintext will appear in the "Plaintext" box.
22
+
23
+ *Note: The decryption process is heuristic and may not always produce a perfect result, especially for short ciphertexts.*
 
main.py ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 导入所需的库
2
+ from pycipher import SimpleSubstitution as SimpleSub
3
+ import random
4
+ import re
5
+ from ngram_score import ngram_score
6
+ import proability
7
+ import gradio as gr
8
+
9
+ # 全局变量,避免重复加载大文件
10
+ _fitness = None
11
+
12
+ def get_fitness():
13
+ global _fitness
14
+ if _fitness is None:
15
+ print("Loading quadgrams data...")
16
+ _fitness = ngram_score('quadgrams.txt')
17
+ print("Quadgrams data loaded successfully.")
18
+ return _fitness
19
+
20
+ def decrypt_text_internal(ciphertext):
21
+ fitness = get_fitness()
22
+ ctext = re.sub('[^A-Z]', '', ciphertext.upper())
23
+ maxkey = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
24
+ maxscore = -99e9
25
+ parentscore, parentkey = maxscore, maxkey[:]
26
+
27
+ i = 0
28
+ # 进一步减少迭代次数以加快响应速度
29
+ while i < 500: # 减少迭代次数
30
+ i = i + 1
31
+ random.shuffle(parentkey)
32
+ deciphered = SimpleSub(parentkey).decipher(ctext)
33
+ parentscore = fitness.score(deciphered)
34
+ count = 0
35
+ while count < 500: # 减少内部迭代次数
36
+ a = random.randint(0, 25)
37
+ b = random.randint(0, 25)
38
+ child = parentkey[:]
39
+ child[a], child[b] = child[b], child[a]
40
+ deciphered = SimpleSub(child).decipher(ctext)
41
+ score = fitness.score(deciphered)
42
+ if score > parentscore:
43
+ parentscore = score
44
+ parentkey = child[:]
45
+ count = 0
46
+ count = count + 1
47
+ if parentscore > maxscore:
48
+ maxscore, maxkey = parentscore, parentkey[:]
49
+ ss = SimpleSub(maxkey)
50
+ plaintext = ss.decipher(ctext)
51
+ plaintext1 = add_punctuation_and_spaces(ciphertext, plaintext)
52
+ # In a web context, we return the first good result.
53
+ # The original loop was infinite, which is not suitable for a server.
54
+ return plaintext1
55
+ # Fallback if no good solution is found within the iteration limit
56
+ ss = SimpleSub(maxkey)
57
+ plaintext = ss.decipher(ctext)
58
+ return add_punctuation_and_spaces(ciphertext, plaintext)
59
+
60
+
61
+ def output(string1, dic, string2):
62
+ modified_string1 = list(string1)
63
+ modified_string2 = list(string2)
64
+ for i in range(len(string1)):
65
+ if modified_string1[i] in dic and modified_string2[i] != ' ':
66
+ modified_string2[i] = dic[modified_string1[i]]
67
+ modified_string2 = ''.join(modified_string2)
68
+ return modified_string2
69
+
70
+ def add_punctuation_and_spaces(ciphertext, plaintext):
71
+ result = ""
72
+ j = 0
73
+ for i in range(len(ciphertext)):
74
+ if not ciphertext[i].isalpha():
75
+ result += ciphertext[i]
76
+ else:
77
+ if ciphertext[i].islower():
78
+ result += plaintext[j].lower()
79
+ else:
80
+ # The original code had a bug here, always making it lowercase.
81
+ # This is a guess at the intended behavior.
82
+ result += plaintext[j]
83
+ j += 1
84
+ return result
85
+
86
+ def decrypt_interface(ciphertext, key):
87
+ """
88
+ This is the main function that will be exposed through the Gradio interface.
89
+ """
90
+ if not ciphertext:
91
+ return "Please enter some ciphertext."
92
+
93
+ plaintext = decrypt_text_internal(ciphertext)
94
+
95
+ if key:
96
+ try:
97
+ key_dic = proability.read_key(key)
98
+ plaintext = output(ciphertext, key_dic, plaintext)
99
+ except Exception as e:
100
+ return f"Error processing key: {e}. Please check the key format (e.g., a=B c=D)."
101
+
102
+ return plaintext
103
+
104
+ # Create the Gradio interface
105
+ iface = gr.Interface(
106
+ fn=decrypt_interface,
107
+ inputs=[
108
+ gr.Textbox(lines=10, label="Ciphertext", placeholder="Enter the text to decrypt..."),
109
+ gr.Textbox(lines=2, label="Known Key Mappings (Optional)", placeholder="e.g., a=B c=D")
110
+ ],
111
+ outputs=gr.Textbox(lines=10, label="Plaintext"),
112
+ title="Simple Substitution Cipher Decryptor",
113
+ description="An automatic decryption tool for simple substitution ciphers. You can optionally provide known letter mappings to improve accuracy."
114
+ )
115
+
116
+ # Launch the app
117
+ if __name__ == "__main__":
118
+ iface.launch(server_name="0.0.0.0", server_port=7860)