• Guest, before posting your code please take these rules into consideration:
    • It is required to use our BBCode feature to display your code. While within the editor click < / > or >_ and place your code within the BB Code prompt. This helps others with finding a solution by making it easier to read and easier to copy.
    • Don't share a wall of code. All we want is the problem area, the code related to your issue.


    To learn more about how to use our BBCode feature, please click here.

    Thank you, Code Forum.

JavaScript Decrypt the rail fence cipher for beginners

Here's the code for the encryption. First every second letter is set and then every other letter(input: abcdefgh; output: acegdfh). I can't figure out the decryption. I figured, seperating the encrypted text in two and alternately taking a letter from each would work. Any ideas for the code? Thank you in advance!


JavaScript:
onEvent("button_encrypt", "click", function(encrypt) {
  var text = getText("text_input1");
  var output = "";
  var i = 0;
  while ((i < text.length)) {
    output = output + text.charAt(i);
    i = i + 2;
  }
  i = 1;
  while ((i < text.length)) {
    output = output + text.charAt(i);
    i = i + 2;
  }
  setText("text_input1", output);
});
 

Ghost

Active Coder
Okay, so first I am going to change a few things about the source so that it works without needing any other elements (like a button) or any functions.

Here's what you have encryption wise, which can be run without relying on your other code:
JavaScript:
var text = "abcdefgh";
var output = "";
var i = 0;
while ((i < text.length)) {
    output = output + text.charAt(i);
    i = i + 2;
}
i = 1;
while ((i < text.length)) {
    output = output + text.charAt(i);
    i = i + 2;
}
console.log(output);

If you test this, you will note that the output is correct.

Now let's decrypt!
This took me longer than expected, but here is the working decryption.
It works by figuring out how many rounds there are in the encryption, and doing a modification of the multipling the round number by 2, and then subtracting either 2, or 1. We subtract 2 to undo the first loop you have, and subtract 1 for the second loop you have.

I figured this out by basically saying: okay in round 1 we have the letter 'a' and this needs to be in position 0 (first letter), and in round 2 we have 'c' which must be in position 2, and in 3 we have 'e' which must be in position 4. So, this is how I got the logic for multipling the round number by 2 and then subtracting 2:
a: round 1 * 2 = 2 and -2 = 0 (position once decrypted)
c: round 2 * 2 = 4 and -2 = 2 (position once decrypted)
e: round 3 * 2 = 6 and -2 = 4 (position once decrypted)
g: round 4 * 2 = 8 and -2 = 6 (position once decrypted)
Once you go through the first half (your first loop) of decryption, we change the modifier to instead be -1 instead of -2.
In your example of 'abcdefgh' it becomes 'acegbdfh'. This is 8 letters in length, which means the first loop is responsible for handling the first half (4 letters).

So, after 4 rounds we're on round 5 and must undo your 2nd while loop (after i=1). We use "active_roundnum" so that the round 5 is actually "round 1 of the 2nd loop decryption" (roundnum 5 - num_rounds_1 (4) = 1).

There are a few ways to decrypt it, but I found that this way used less code - I could have just copied what I had first and changed some numbers around for the second batch of duplicate code but I decided to make it dynamic to any length of string and number of rounds.

Anyways... here is how the 2nd batch of "rounds" looks:
b: round 5 - which is actually the active round = 1 * 2 = 2 and then -1 = 1 (position once decrypted)
d: round 6 - which is actually the active round = 2 * 2 = 4 and then -1 = 3 (position once decrypted)
f: round 7 - which is actually the active round = 3 * 2 = 6 and then -1 = 5 (position once decrypted)
h: round 8 - which is actually the active round = 4 * 2 = 8 and then -1 = 7 (position once decrypted)


JavaScript:
var text = "acegbdfh", // the encrypted text
    letter_placements = [];
// output should = abcdefgh
    var textlen = text.length, // technically faster than re-checking length each loop
    roundnum = 1,
    num_rounds_1 = textlen % 2 == 0 ? textlen / 2 : (textlen + 1) / 2,
    total_rounds = num_rounds_1 * 2;
while(roundnum <= total_rounds){
    if(roundnum > textlen){ roundnum++; continue; }
    var subtract_modify = roundnum <= num_rounds_1 ? 2 : 1,
        active_roundnum = subtract_modify == 2 ? roundnum : roundnum - num_rounds_1,
        final_letter_placement =  (active_roundnum*2) - subtract_modify,
        this_letter = text.charAt(roundnum - 1);
    console.log('activeroundnum ' + active_roundnum, 'round ' + roundnum, 'subtractmod ' + subtract_modify, 'final letter ' + final_letter_placement, ' the letter: ', this_letter)
    letter_placements[final_letter_placement] = this_letter;
    roundnum++;
}
output = letter_placements.join("");
console.log(letter_placements);
console.log(output);

Let's test:
I am starting with: text = "i have successfully decrypted this sentence" which encrypts to output = "ihv ucsflydcytdti etne aescesul erpe hssnec"

This then goes for a total of 43 rounds, which is 22 rounds to undo your first loop with i = 0 and 21 to undo the second loop with i = 1.

The letter_placements array just stores things like this:
(43) ["i", " ", "h", "a", "v", "e", " ", "s", "u", "c", "c", "e", "s", "s", "f", "u", "l", "l", "y", " ", "d", "e", "c", "r", "y", "p", "t", "e", "d", " ", "t", "h", "i", "s", " ", "s", "e", "n", "t", "e", "n", "c", "e"] which is 43 values being stored. This is how I store exact placements, instead of just using like... output += "a" or anything like output = output + "a";
 
Last edited:

Top