Skip to content

Instantly share code, notes, and snippets.

@wrayal
Forked from 140bytes/LICENSE.txt
Created June 16, 2011 12:03
Show Gist options
  • Save wrayal/1029102 to your computer and use it in GitHub Desktop.
Save wrayal/1029102 to your computer and use it in GitHub Desktop.
Vigenère cypher

The Vigenère Cypher

In 138b, this will encrypt/decrypt anything using the Vigenère cypher. Input is entered as solely lower case letters (no numbers, spaces, special characters etc). Outputs may be verified against http://sharkysoft.com/misc/vigenere/

Background

As described on http://ub.ly/um (the parser chokes on the full URL), the essence of the Vigenère cypher is that it is a cyclic version of the Caesar shift cypher. It's not unbreakable but it's pretty good. Also, as a corollary we get rot13 (use "n" as an encoding parameter - yes, as originally defined there's a one byte offset from what you might expect...) and of course Caesar.

Entry History

My initial attempts were encryption only (138b):

function(j,s,h,g,i,n){for(g="",i=0;i-j.length;g+=String.fromCharCode(n?n+64:90))n=(j.charCodeAt(i)+s.charCodeAt(i++%s.length)+15)%26;h(g)}

and encryption + decryption (151b):

function(j,s,h,t,g,i,n){for(g="",i=0;i-j.length;g+=String.fromCharCode(n?n+64:90))n=(j.charCodeAt(i)+t*s.charCodeAt(i++%s.length)+(t>0?15:27))%26;h(g)}

with t=+/- 1 being encryption/decryption. Thanks to all the help in the comments (especially @subzey!) this is now down to 138b, with both encryption and decryption.

What I learnt

The phrases "fromCharCode", "charCodeAt" and "String" are FAR too long =(

Savings don't always come where you expect them to (see @jed's ultimately unused 'harCode' hack in the comments). In fact, from my experience so far in 140byt.es, they most often come from some slight (or indeed major!) reworking of the algorithm (c.f. the successive contributions to fibonacci, base64 enc/dec etc).

http://esparser.qfox.nl/ is amazing

function(
a //input string
,b //key string
,c //callback function
,d //direction (1=encrypt, -1=decrypt)
,e //output string
,f //iterator
){
for(
f=e=""; //initialize; f will be coerced to a numerical value
f<a.length; //loop for all character in string
e+=String.fromCharCode(90-25*(a.charCodeAt(f)+d*b.charCodeAt(f++%b.length)+27+~d*6)%26)
//very neat trick to make the fact that 26%26=0 work for you rather than against you - see @subzey's description =)
//note ~d=-2 for d=1, 0 for d=-1; and 27-15=12 (these are the magic unicode offsets =)
)
;
c(e) //and we're done! send back...
}
function(a,b,c,d,e,f){for(f=e="";f<a.length;e+=String.fromCharCode(90-25*(a.charCodeAt(f)+d*b.charCodeAt(f++%b.length)+27+~d*6)%26));c(e)}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2011 YOUR_NAME_HERE <YOUR_URL_HERE>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "vigenereCypher",
"description": "This will cypher using the vigenere method",
"keywords": [
"viegnere",
"cypher",
"encryption"
]
}
<!DOCTYPE html>
<title>Vigenère encryption</title>
<pre>
Expected value: <b>HUMZWBGVMVOAORMWILRNVQESBESOSEGHMRSCELNGHQA</b>
Actual value: <b id="ret"></b>
</pre>
<script>
function b(text)
{
document.getElementById( "ret" ).innerHTML=text
}
var myFunction=function(a,b,c,d,e,f){for(f=e="";f<a.length;e+=String.fromCharCode(90-25*(a.charCodeAt(f)+d*b.charCodeAt(f++%b.length)+27+~d*6)%26));c(e)}
myFunction("thiscodeisonlyforstandardlowercaseplaintext","onehundredandthirtyninebytes",b,1)
//to test decryption:
//myFunction("humzwbgvmvoaormwilrnvqesbesoseghmrscelnghqa","onehundredandthirtyninebytes",b,-1)
</script>
</html>
@atk
Copy link

atk commented Jun 17, 2011

Those suggestions were given to you to incorporate them in your code. Were a suggestion mine, I'd rather be a bit disappointed if you didn't include it. The goal is the smallest possible function, so use whatever you find. Since all revisions and comments are preserved, it's ok to do so.

@mikesherov
Copy link

@wrayal, yeah, don't worry too much about it! Use all the suggestions. That's the spirit of WTFPL. You just DO WHAT THE FUCK YOU WANT TO.

@wrayal
Copy link
Author

wrayal commented Jun 17, 2011

Wise points; updated accordingly. One last potential bit of golf; thanks to @subzey's neat ~d trick, isn't the set of brackets enclosing that bit redundant? i.e.138b: function(a,b,c,d,e,f){for(f=e="";f<a.length;e+=String.fromCharCode(90-25*(a.charCodeAt(f)+d*b.charCodeAt(f++%b.length)+27+~d*6)%26));c(e)}

@atk
Copy link

atk commented Jun 17, 2011

Btw.: I like the idea to omit "return" in favor of a callback. Much more elegant than outsourcing stuff like "String.fromCharCode" like I did in my first try of the base64 decoder.

@michaelficarra
Copy link

@wrayal: The name's spelled wrong in the README. It's "Vigenère cipher", not "vignere cypher".

@neizod
Copy link

neizod commented Oct 5, 2011

"Cypher" also wrong. Use "cipher".

@tsaniel
Copy link

tsaniel commented Jan 31, 2012

I believe there is enough room to return:
function(a,b,d,e,f){for(f=e="";f<a.length;e+=String.fromCharCode(90-25*(a.charCodeAt(f)+d*b.charCodeAt(f++%b.length)+27+~d*6)%26));return e}

@atk
Copy link

atk commented Jan 31, 2012

Save another byte:

function(a,b,d,e,f,g){for(f=e="";f<a.length;e+=String.fromCharCode(90-25*(a[g='charCodeAt'](f)+d*b[g](f++%b.length)+27+~d*6)%26));return e}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment