Skip to content

Instantly share code, notes, and snippets.

@pascalduez
Last active April 9, 2018 16:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pascalduez/c72df9e25fc8866376d5 to your computer and use it in GitHub Desktop.
Save pascalduez/c72df9e25fc8866376d5 to your computer and use it in GitHub Desktop.
Vigenère cipher in Sass.
// ----
// Sass (v3.3.8)
// Compass (v1.0.0.alpha.19)
// ----
// Vigenère cipher.
// https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher
// Get char code from `$str` at `$index` in range [1-52][A-Za-z].
// ––––––––
// @param [string] $str
// @param [number] $index
// ––––––––
// @return [number]
@function char-code-at($str, $index: 1) {
$chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
@return str-index($chars, str-slice($str, $index, $index));
}
// Get char at `$index` in range [1-52][A-Za-z].
// ––––––––
// @param [number] $index
// ––––––––
// @return [string]
@function from-char-code($index) {
$chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
@return str-slice($chars, $index, $index);
}
// Filter and build the numeric key in range [0-25].
// ––––––––
// @param [string] $key
// ––––––––
// @return [list]
@function key($key) {
$result: ();
@for $i from 1 through str-length($key) {
$c: char-code-at($key, $i);
@if $c {
$result: append($result, ($c - 1) % 26);
}
}
@return $result;
}
// Encrypt a `$message` with the vigenère cipher based on `$key`.
// ––––––––
// @param [string] $message
// @param [string] $key
// ––––––––
// @return [string]
@function vigenere-encrypt($message, $key) {
@return vigenere($message, key($key));
}
// Decrypt a vigenère encrypted `$message` based on `$key`.
// ––––––––
// @param [string] $message
// @param [string] $key
// ––––––––
// @return [string]
@function vigenere-decrypt($message, $key) {
$key: key($key);
@for $i from 1 through length($key) {
$key: set-nth($key, $i, (26 - nth($key, $i) % 26));
}
@return vigenere($message, $key);
}
// Vigenère cipher encoder/decoder.
// ––––––––
// @param [string] $message
// @param [string] $key
// ––––––––
// @return [string]
@function vigenere($message, $key) {
$length: length($key);
$result: '';
$j: 1;
@for $i from 1 through str-length($message) {
$col: char-code-at($message, $i);
$match: '';
@if $col {
// Uppercase $col <= 26
// Lowercase $col > 26
$pos: if($col > 26, 27, 1);
$match: (($col - $pos) + nth($key, (($j - 1) % $length + 1))) % 26 + $pos;
$match: from-char-code($match);
$j: $j + 1;
}
@else {
// Non [A-Za-z] char.
$match: str-slice($message, $i, $i);
}
$result: $result + $match;
}
@return $result;
}
// Tests
vigenere {
$fixture: (
('attackatdown', 'lemon', 'lxfopvefrbhr'),
('Helmholtzplatz', 'Berlin', 'Iicxpbmxqatnud'),
('Hey! how’s it going ?', 'Amiens', 'Hqg! lbo’s ub kbans ?'),
('Les sanglots longs Des violons Blessent mon cœur D’une langueur Monotone.', 'BBC', 'Mfu tbphmqut npoit Egt wkpmqot Dmfutfpu nqo dœws E’wof nboivfws Nqopvpog.'),
('Punkt, Punkt, Komma, Strich, fertig ist das Mondgesicht.', 'Saßy', 'Hulct, Nmnil, Kmemy, Ktpacf, xeplie asr vaq Eolvgckiazt.')
);
/* Encrypt */
$tests: '';
@each $test in $fixture {
$pass: vigenere-encrypt(nth($test, 1), nth($test, 2)) == nth($test, 3);
$tests: $tests + if($pass, '✔ ', 'X ');
}
tests: $tests;
/* Decrypt */
$tests: '';
@each $test in $fixture {
$pass: vigenere-decrypt(nth($test, 3), nth($test, 2)) == nth($test, 1);
$tests: $tests + if($pass, '✔ ', 'X ');
}
tests: $tests;
}
@charset "UTF-8";
vigenere {
/* Encrypt */
tests: "✔ ✔ ✔ ✔ ✔ ";
/* Decrypt */
tests: "✔ ✔ ✔ ✔ ✔ ";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment