Skip to content

Commit e02f804

Browse files
Aplikace na kontrolu hashu
1 parent 2de03e3 commit e02f804

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ Ve složce [`apps`](apps) se nachází užitečné webové aplikace, které moho
345345
| Aplikace | Popis |
346346
|----------|-------|
347347
| [Labyrinth](apps/labyrinth) | Vizualizace bludišť a animace cest — slouží k ladění a ověřování algoritmů prohledávání grafů (BFS, DFS apod.) |
348+
| [Hash](apps/hash) | Výpočet hashů dvou řetězců a hledání nejdelšího společného podřetězce |
348349

349350
---
350351

apps/hash/index.html

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
<!DOCTYPE html>
2+
<html lang="cs">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Hash Collision Finder</title>
7+
<style>
8+
body, html {
9+
margin: 0;
10+
padding: 0;
11+
height: 100vh;
12+
display: flex;
13+
align-items: center;
14+
justify-content: center;
15+
background-color: #eee;
16+
font-family: monospace;
17+
}
18+
19+
.container {
20+
background: rgba(255, 255, 255, 0.9);
21+
padding: 30px;
22+
border-radius: 5px;
23+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
24+
display: flex;
25+
flex-direction: column;
26+
gap: 10px;
27+
max-width: 500px;
28+
width: 100%;
29+
}
30+
31+
h1 {
32+
margin: 0 0 10px 0;
33+
font-size: 1.2em;
34+
}
35+
36+
label {
37+
font-weight: bold;
38+
}
39+
40+
input[type="text"] {
41+
padding: 8px;
42+
font-family: monospace;
43+
font-size: 1em;
44+
border: 1px solid #ccc;
45+
border-radius: 3px;
46+
}
47+
48+
button {
49+
padding: 8px 16px;
50+
font-family: monospace;
51+
font-size: 1em;
52+
cursor: pointer;
53+
background: #333;
54+
color: #fff;
55+
border: none;
56+
border-radius: 3px;
57+
}
58+
59+
button:hover {
60+
background: #555;
61+
}
62+
63+
.result {
64+
margin-top: 10px;
65+
padding: 15px;
66+
background: #f5f5f5;
67+
border-radius: 3px;
68+
display: none;
69+
}
70+
71+
.result.visible {
72+
display: block;
73+
}
74+
75+
.hash-display {
76+
font-size: 1.3em;
77+
letter-spacing: 2px;
78+
margin: 5px 0;
79+
}
80+
81+
.overlap {
82+
margin-top: 15px;
83+
padding: 10px;
84+
background: #e8f5e9;
85+
border-radius: 3px;
86+
}
87+
88+
.overlap.none {
89+
background: #fbe9e7;
90+
}
91+
92+
.highlight {
93+
background: #ffeb3b;
94+
font-weight: bold;
95+
border-radius: 2px;
96+
padding: 0 1px;
97+
}
98+
</style>
99+
</head>
100+
<body>
101+
102+
<div class="container">
103+
<h1>Hash Collision Finder</h1>
104+
105+
<label for="input1">Input 1:</label>
106+
<input type="text" id="input1" placeholder="e.g. Hello World">
107+
108+
<label for="input2">Input 2:</label>
109+
<input type="text" id="input2" placeholder="e.g. kcooitbulc">
110+
111+
<button onclick="compute()">Compute</button>
112+
113+
<div class="result" id="result">
114+
<div>
115+
<label>Hash 1:</label>
116+
<div class="hash-display" id="hash1"></div>
117+
</div>
118+
<div>
119+
<label>Hash 2:</label>
120+
<div class="hash-display" id="hash2"></div>
121+
</div>
122+
<div class="overlap" id="overlap"></div>
123+
</div>
124+
</div>
125+
126+
<script>
127+
function hash(input) {
128+
const result = Array.from("0123456789abcdef").map(c => c.charCodeAt(0));
129+
130+
for (let i = 0; i < input.length - 1; i++) {
131+
const a = input.charCodeAt(i);
132+
const b = input.charCodeAt(i + 1);
133+
const sum = a + b;
134+
const tmp = sum % 128;
135+
const pos = sum % 16;
136+
137+
result[pos] = (result[pos] + tmp) % 128;
138+
139+
// cyclic shift right by pos positions
140+
const shifted = [];
141+
for (let j = 0; j < 16; j++) {
142+
shifted[j] = result[(j - pos + 16) % 16];
143+
}
144+
for (let j = 0; j < 16; j++) {
145+
result[j] = shifted[j];
146+
}
147+
}
148+
149+
// convert to lowercase letters
150+
for (let i = 0; i < 16; i++) {
151+
result[i] = 97 + (result[i] % 26);
152+
}
153+
154+
return String.fromCharCode(...result);
155+
}
156+
157+
function longestCommonSubstring(s1, s2) {
158+
let best = "";
159+
160+
for (let len = s1.length; len >= 1; len--) {
161+
for (let i = 0; i <= s1.length - len; i++) {
162+
const sub = s1.substring(i, i + len);
163+
if (s2.includes(sub)) {
164+
return sub;
165+
}
166+
}
167+
}
168+
169+
return best;
170+
}
171+
172+
function highlightSubstring(text, sub) {
173+
if (!sub) return text;
174+
const idx = text.indexOf(sub);
175+
if (idx === -1) return text;
176+
return text.substring(0, idx)
177+
+ '<span class="highlight">' + sub + '</span>'
178+
+ text.substring(idx + sub.length);
179+
}
180+
181+
function compute() {
182+
const el1 = document.getElementById("input1");
183+
const el2 = document.getElementById("input2");
184+
185+
el1.placeholder = "";
186+
el2.placeholder = "";
187+
188+
const input1 = el1.value;
189+
const input2 = el2.value;
190+
191+
const h1 = hash(input1);
192+
const h2 = hash(input2);
193+
194+
const common = longestCommonSubstring(h1, h2);
195+
196+
document.getElementById("hash1").innerHTML = highlightSubstring(h1, common);
197+
document.getElementById("hash2").innerHTML = highlightSubstring(h2, common);
198+
199+
const overlapDiv = document.getElementById("overlap");
200+
if (common.length > 0) {
201+
overlapDiv.className = "overlap";
202+
overlapDiv.innerHTML = "Overlap: <strong>" + common + "</strong> (length " + common.length + ")";
203+
} else {
204+
overlapDiv.className = "overlap none";
205+
overlapDiv.textContent = "No overlap found.";
206+
}
207+
208+
document.getElementById("result").classList.add("visible");
209+
}
210+
</script>
211+
212+
</body>
213+
</html>

0 commit comments

Comments
 (0)