How do I use modulo arithmetic to implement caesar cipher - c

I am trying to perform a wrap around of the ASCII alphabet characters in order to perform a shift from a key. For example, if the key is 2 then shift the letter A to become C. But, how do I wrap around Z in order to get to B using modulus arithmetic?
I am trying to implement the following formula:
ci = (pi + key) % 26;
Where ci is the ith ciphered letter and pi is the ith letter to be ciphered.

I believe you need to work with "relative" values, rather than absolute values.
Use something like
ci = ((pi - 'A' + key) % 26 ) + 'A';
Character integer constants stores the encoded values, in this case, ASCII. Here, 'A' starts from an offset (decimal value of 65), not from 0. So, before you can wrap the result using a % 26 operation, you need to get that offset out. Once the calculation is done, add the offset back to get the proper ASCII representation.

Others have already shown the basic concept of subtracting the offset of ASCII letters, but you have to be careful in when crossing from capital to non capital letters, as there are some symbols in between which I guess you want to avoid. I have added some logic that enables negative shifts and keeps the letter within capital letter or non capital letter space and tests whether it is a letter at all.
#include <stdio.h>
#define ASCII_CAP_LETTER_OFFS 65
#define ASCII_LETTER_OFFS 97
#define NUM_OF_LETTERS 26
char shift_letter (char letter, short shift)
{
char ci;
short shift_lcl = shift % NUM_OF_LETTERS;
if (shift_lcl >= 0)
{ // shift in positive direction
}
else
{ // shift in negative direction
shift_lcl = NUM_OF_LETTERS + shift_lcl;
}
if (letter >= ASCII_CAP_LETTER_OFFS && letter < ASCII_CAP_LETTER_OFFS + NUM_OF_LETTERS)
{// its a capital letter
ci =
(letter + shift_lcl - ASCII_CAP_LETTER_OFFS) % NUM_OF_LETTERS +
ASCII_CAP_LETTER_OFFS;
}
else if (letter >= ASCII_LETTER_OFFS && letter < ASCII_LETTER_OFFS + NUM_OF_LETTERS)
{// its a non capital letter
ci =
(letter + shift_lcl - ASCII_LETTER_OFFS) % NUM_OF_LETTERS +
ASCII_LETTER_OFFS;
}
else
{
printf ("This was not a letter!\n");
ci = 0;
}
return ci;
}
int main ()
{
char test_letter = 'a';
short test_shift = -53;
char shifted_letter = 0;
shifted_letter = shift_letter (test_letter, test_shift);
printf("%c + %d = %c", test_letter, test_shift, shifted_letter);
}

Deeper
ci = ((pi - 'A' + key) % 26) + 'A';
as well answered by #Sourav Ghosh generates the expected encoded A-Z when key is non-negative and not too large. It reduces pi with - 'A' so the value is in the [0...25] range and the re-offsets it after the % calculation.
To work for the full int range of key takes a little more code.
Reduce key range [INT_MIN...INT_MAX] with the functional equivalent range of [-25 ... 25] with key % 26. This step is important to prevent intoverflow with pi - 'A' + key. This can be done once if a number of letters need encoding.
Add 26. This insures negative keys are moved to positive ones.
ci = ((pi - 'A' + key%26 + 26) % 26 ) + 'A';
Note: In C, % is not the mod operator, but the remainder operator. Functional differences occur with a%b when a and/or b are negative. ref

Related

plus alphabet kind of

first of all, i'm a college freshman. i'd like to help my college task? i would really appreciate if you help my task.
And this task uses C language.
first i need to get two inputs (using scanf; one is alphabet like a or A and the other is arabic number like 1, 2)
and i need to add number on alphabet
ex) if i put
A 3
and the computer indicates D
here is the point, if i put Y 4 i need to get 'C' (using ASCII code and % )
the lower part is what i've tried for this task
int input;
char eng;
scanf("%c %d", &eng, &input);
if (eng >= 'a' && eng <= 'z') {
eng = (eng + input) % ('z' - 'a') + eng -1;
}
it compiles but when i put y 4 it results x however i need c .
You want this:
eng = ((eng - 'a') + input) % ('z' - 'a' + 1) +'a'
(eng - 'a') transforms your input from ['a'..'z'] into the domain [0..25].
+ input adds the offset
% ('z' - 'a' + 1) does the modulo
and finally + 'a' transforms the domain [0..25] back into ['a'..'z']

I am trying to perform a Caesar shift on the character z (ASCII 122). How do I give it "more room" to prevent it from overflowing past 127?

In the CS50 2019 Caesar assignment, I am supposed to perform Caesar shifts on characters by a given number of letters (key).
To do this, I add the value of key to each letter, as such:
for each character in plaintext:
plaintext[character] += key
Since I want z to loop back to a, I then wrote:
while (ciphered_character > 122)
{
ciphered_character -= 26;
}
Running the program with plaintext of z and a key of 26 causes 26 to be added to z (which is represented by 122). This causes plaintext[character] to overflow (past 127, I presume) and become negative before the while loop even kicks in. This gives a garbage output.
I know I can check for potential overflows beforehand and subtract 26 first, but that complicates my code. Can I give the variable 'more room' to prevent it from overflowing?
Do I use a different data type? What is the best practice here?
If you only care about lower case then this will work for you:
for each character in plaintext:
plaintext[character] = (plaintext[character] - 'a' + key) % 26 + 'a'
Subtracting 'a' to give you a value of 0-25, then add the key. If there is a overflow the modulo will give you the updated value in the 0-25 range which is added back to 'a' to get the correct character.
If you do need to handle both upper and lower case then you will need two different cases - one using 'a' and the other using 'A'. Select the the correct case for each character by checking isupper(plaintext[character])
Fun project;
I did it like this, assuming ASCII and using the full range of printable characters, from Space to ~
void caeser_shift(char* text, int key)
{ while (*text) { *text++ = ((*text-' ') + key) %('~'-' ') + ' '; } }
int main(void)
{
char plaintext[] = "Hello World; This is a test.";
caeser_shift(plaintext, 26);
printf("%s\n", plaintext);
return 0;
}
Output
Success #stdin #stdout 0s 4520KB
b!((+:q+.( U:n$%/:%/:{:0!/0H

C: printing %c doesn't work when I put the value in brackets

That's my first post here and I tried to be as specific with the title as I could. Sorry for any errors :)
I'm doing my pset for a CS course and I have a problem with printing my value. When I put the value like this: (%c, p[j] + k%26) the program prints it. When I put it in the brackets as below it doesn't. And that's an important difference in this case.
Do you have any advice for me? If so please do not write any code as we are not permitted to receive any code from outside. Just let me know if in C the thing I'm doing is just illegal or maybe ask some open question that might help!
Relevant part of the Code
for (int j = 0, m = strlen(p); j < m; j++)
{
if (isalpha(p[j]))
{
printf("%c", (p[j] + k)%26);
}
else
{
printf("%c", p[j]);
}
}
You mean in the parentheses.
This:
p[j] + k % 26
is different than:
(p[j] + k) % 26
because of the operator preceding, where the modulo will be executed before the addition. However, the formula that is enclosed into the parentheses will have the highest preceding, thus will be executed first.
As a result in the first case k % 26 will be executed first, and its result will be added to p[j].
In the second case, p[j] will be added to k, and that sum will be affected by % 26.
As you can see these two things are different, thus explaining the different behavior you experience.
And as Eugene mentioned, characters with ascii values from 0 to 25 are not always printable.
When you perform (p[j]+k)%26, you get a value between 0-25. refer the ASCII table these values represent control characters.
I am assuming you are coding for some cipher. In that case you just need to subtract 26 from p[i]+j. Remember ASCII values for alphabets are not 0-25
Those are two different things as the % operator has precedence wrt the sum, so it is a matter of math. The code
printf("%c", (p[j] + k)%26);
always prints a character, but in this case you are applying the modulo operation (%) to the final value, resulting in a number from 0 to 25. Note that none of this character are printable (i.e. they are blank spaces or others --- see an ASCII table).
It's expected adding an offset to a character is some character and that is in first case might in range p[j] to p[j]+25 and in second case also
you just try to print something having ascii value 0 to 25 which might be something like non-printable.
But in both cases you may face something non printable.
% has higher precedence than + so in first case
p[j] + (k%26)
In second case
(p[j] + k)%26
well that because the result will be some numbers from 0 to 25 which btw is unprintable in ascii code so you have to add 65 if the number is uppercase or 97 if the number is lowercase here is the ascii code table to understand more
for (int j=0, m = strlen(p); j < m; j++)
if (isalpha(p[i]))
{
if (isupper(p[i]))
{
printf("%c",((text[i] - 65 + k) % 26) + 65);
}
else
{
printf("%c",((text[i] - 97 + k) % 26) + 97);
}
}
else
printf("%c",text[i]);

Manipulating array of chars

I'm writing a code in C programming language that receives a string (of chars) as input and each letter advances 3 in the alphabet. E.g. If user types "abc", the program should return "def". The problem is that if the user types 'z' (e.g.), the program returns some char, instead of my goal (which would be this case the letter 'c'). My current algorithm includes this if statement:
if ((text[i]>='a' && text[i]<='w')||(text[i]>='A' && text[i]<='W'))
text[i] = (text[i]) + 3;
But this forces me to write all this lines:
else if (text[i]=='x') text[i]='a';
else if (text[i]=='X') text[i]='A';
else if (text[i]=='y') text[i]='b';
else if (text[i]=='Y') text[i]='B';
else if (text[i]=='z') text[i]='c';
else if (text[i]=='Z') text[i]='C';
How can I optimize my code?
Your problem can be addressed with simple arithmetic logic. The range of char ranges from 0 - 255. Each value corresponds to a separate character. The letters 'A-Z' and 'a-z' range from 65 - 90 and 97 - 122 respectively. So for your problem there are two ranges. You can check with the standard library function that your character falls in upper case or lower case range. then you can set the base for your range. Next you will find the offset of your character from base, add 3 in it. the new value can be made circular using % operator. each range has maximum of 26 characters so you can make your range circular by taking a mod from 26. Now add the resulting value (offset) to the base to get the desired character.
#include <ctype.h>
...
...
...
char c = text[i];
char base = isupper(c)? 'A' : 'a';
text[i] = base + (((c - base) + 3) % 26); // New Desired Character

Wrapper operation trouble

I am having a terrible time understanding how to get the wrapper to work with these encryption programs. I got a Caesar cipher program to work to both encrypt and decrypt, now I am working on a Vigenere cipher. I have the program working but when I use a key that will cause the letters to wrap around I get odd results. Here is the code I am using:
int main(int argc, char *argv[])
{
char s2[25];
strcpy(s2, argv[1]);
printf("Please enter a string of text to be encrypted!\n");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if (isupper(p[i])){
char c = (p[i] - 'A' + s2[i]);
printf("%c", c);
}
}
printf("\n");
}
This code will work if the command line input is ./program BACON and I enter BLAH for the text to be encrypted. If for example I use ./program ZZZZZ as the key then I will get all kinds of odd results because it does not wrap back around. I have tried using the modulus operator and have left it out of the code I just posted because I still could not get it to wrap with that. I am just starting to learn programming.
Update
Maybe you can help me understand the math better; your code works perfectly, but I have been trying to figure this out on a calculator manually just to see what's going on. This is what I have so far:
./program HHHHH
keyLen should equal 5 in my understanding and so if I give p[i] a value of "H"
keyLen= 5
p[i]= H //or 72 in ASCII
int sum = (p[i] - 'A') + (s2[i % keyLen] - 'A'); //sum = (72 - '65') + ([72 % 5] - '65');
char c = 'A' + sum%26; // c = 65 + -11
Maybe my math is way off because when I do things in the order I think they should be done sum = negative 63 and so a 26 mod of -63 which gives me negative 11. Which clearly is not right because that equals 54 when you add 65 and negative 11.
Even if I make the negative 11 a positive integer of 11 and add 65 I get 76 which is ASCII character "L" but the right answer is "O". I am clearly doing something wrong but I've been working on the solution for a while now and keep coming up with the same results.
There are two "wrap-around" issues in your program:
Your letters do not wrap around when the key and the current letter combine to produce a value beyond 26, and
You read past the end of the key when the length of the word being encrypted exceeds the length of the key.
Here is how you fix it: right after copying the key into s2, do this:
int keyLen = strlen(s2);
Now inside your loop do this:
int sum = (p[i] - 'A') + (s2[i % keyLen] - 'A'); // Calculate the sum of key+word
char c = 'A' + sum%26; // Wrap around at 26, the number of letters in the alphabet
This will make the output look "normal".
Once you figure out how the last formula works, you should be able to modify it to decode the word.

Resources