C Fundamentals
Algorithms · data structures · cryptography · systems — pure C11, zero deps
Loading...
Searching...
No Matches
caesar.c
Go to the documentation of this file.
1/**
2 * @file caesar.c
3 * @brief Implementation of Caesar cipher
4 */
5
6#include "caesar.h"
7#include <ctype.h>
8#include <string.h>
9
10char caesar_encrypt_char(char c, int shift) {
11 if (!isalpha(c)) {
12 return c;
13 }
14
15 // Normalize shift to 0-25 range
16 shift = ((shift % 26) + 26) % 26;
17
18 char base = isupper(c) ? 'A' : 'a';
19 return (char)(((c - base + shift) % 26) + base);
20}
21
22char caesar_decrypt_char(char c, int shift) {
23 // Decryption is just encryption with negative shift
24 return caesar_encrypt_char(c, -shift);
25}
26
27void caesar_encrypt(char *text, int shift) {
28 if (text == NULL)
29 return;
30
31 for (size_t i = 0; text[i] != '\0'; i++) {
32 text[i] = caesar_encrypt_char(text[i], shift);
33 }
34}
35
36void caesar_decrypt(char *text, int shift) { caesar_encrypt(text, -shift); }
37
38int caesar_crack(const char *text) {
39 if (text == NULL || *text == '\0') return 0;
40
41 /* Reference letter frequencies for English (percent). */
42 static const double ENGLISH_FREQ[26] = {
43 8.17, 1.49, 2.78, 4.25, 12.70, 2.23, 2.02, 6.09, 6.97, 0.15,
44 0.77, 4.03, 2.41, 6.75, 7.51, 1.93, 0.10, 5.99, 6.33, 9.06,
45 2.76, 0.98, 2.36, 0.15, 1.97, 0.07
46 };
47
48 /* Tally cipher frequencies. */
49 int counts[26] = {0};
50 int total = 0;
51 for (size_t i = 0; text[i] != '\0'; i++) {
52 if (isalpha((unsigned char)text[i])) {
53 counts[toupper((unsigned char)text[i]) - 'A']++;
54 total++;
55 }
56 }
57 if (total == 0) return 0;
58
59 /* For each candidate shift, score plaintext by chi-squared distance from
60 the English distribution. Lowest score wins. */
61 double best_chi = 1e18;
62 int best_shift = 0;
63 for (int s = 0; s < 26; s++) {
64 double chi = 0.0;
65 for (int i = 0; i < 26; i++) {
66 /* Decrypting with shift s rotates the cipher tally by -s. */
67 double observed = (double)counts[(i + s) % 26];
68 double expected = ENGLISH_FREQ[i] / 100.0 * (double)total;
69 double delta = observed - expected;
70 if (expected > 0) chi += (delta * delta) / expected;
71 }
72 if (chi < best_chi) {
73 best_chi = chi;
74 best_shift = s;
75 }
76 }
77
78 return best_shift;
79}
char caesar_encrypt_char(char c, int shift)
Encrypt a single character.
Definition caesar.c:10
int caesar_crack(const char *text)
Crack a Caesar cipher by chi-squared comparison against English letter frequencies.
Definition caesar.c:38
char caesar_decrypt_char(char c, int shift)
Decrypt a single character.
Definition caesar.c:22
void caesar_decrypt(char *text, int shift)
Decrypt a string encrypted with Caesar cipher.
Definition caesar.c:36
void caesar_encrypt(char *text, int shift)
Encrypt a string using the Caesar cipher.
Definition caesar.c:27
Caesar cipher encryption and decryption.