Coder sans raison précise — implémenter le chiffrement de Vigenère et apprendre en chemin
Ce qui arrive quand on code sans but précis — et pourquoi c'est souvent là qu'on apprend le mieux.
Je me baladais sur Wikipedia. Pas de raison particulière, juste ce plaisir un peu coupable de cliquer de lien en lien jusqu’à se retrouver sur une page qu’on n’avait pas du tout prévu de lire.
Et je suis tombé sur le chiffrement de Vigenère. Et je me suis dis
Tiens. En vrai, je pourrais coder ça ?
Ce que j’ai lu et compris
Le chiffrement de Vigenère est un système de chiffrement par substitution polyalphabétique — ce qui veut dire qu’une même lettre du message peut être remplacée par des lettres différentes selon sa position. C’est ce qui le distingue d’un simple chiffre de César, où chaque lettre est toujours décalée du même nombre de positions.
Le principe : on associe une clé au message. Chaque lettre de la clé indique de combien de positions décaler la lettre correspondante du message. La clé boucle sur elle-même si le message est plus long.
Par exemple, avec le message HELLO et la clé KEY :
H+K(décalage de 10) →RE+E(décalage de 4) →IL+Y(décalage de 24) →JL+K(décalage de 10, la clé repart du début) →VO+E(décalage de 4) →S
Résultat : RIJVS.
Pendant longtemps considéré comme “le chiffre indéchiffrable”, il a finalement été percé par le major prussien Friedrich Kasiski, qui a publié sa méthode en 1863. Depuis, il n’offre plus aucune sécurité réelle — mais comme exercice de code, il est parfait et intéressant.
Ce qui m’a rappelé pourquoi JS est bien fait
Pour implémenter ça en JavaScript (Mon langage de coeur), il faut accéder à chaque caractère du message et de la
clé un par un. Mon réflexe aurait été de faire un .split("") pour convertir les strings
en tableaux avant de les parcourir.
Sauf qu’en écrivant le code, j’ai réalisé que ce n’était pas nécessaire :
const mot = "HELLO"
console.log(mot[0]) // "H"
console.log(mot[1]) // "E"
Un string en JavaScript est indexable caractère par caractère, exactement comme un tableau.
Ce n’est pas un vrai Array, mais la syntaxe [] fonctionne nativement. On peut même
itérer directement avec for...of sans aucune conversion.
L’implémentation
const FR_ALPHABET = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
]
function vigenere(message, key, mode) {
let newMessage = []
let indexPointer = 0
for (let i = 0; i < message.length; i++) {
const alphabetIndexMessage = FR_ALPHABET.indexOf(message[i])
if (alphabetIndexMessage === -1) {
newMessage.push(message[i])
continue
}
const alphabetIndexKey = FR_ALPHABET.indexOf(key[indexPointer % key.length])
indexPointer++
if (mode === "encode") {
newMessage.push(FR_ALPHABET[(alphabetIndexMessage + alphabetIndexKey) % 26])
} else {
newMessage.push(FR_ALPHABET[(alphabetIndexMessage - alphabetIndexKey + 26) % 26])
}
}
return newMessage.join("")
}
Quelques détails qui valent la peine d’être notés :
indexPointer % key.length : la clé boucle sur elle-même. Et indexPointer n’est
incrémenté que sur les caractères alphabétiques — les espaces et la ponctuation ne
consomment pas de position dans la clé. C’est un détail qui change tout : sans ça, un
espace décalerait la clé et fausserait tout le déchiffrement.
(alphabetIndexMessage - alphabetIndexKey + 26) % 26 : le + 26 est indispensable.
En JavaScript, le modulo d’un nombre négatif reste négatif. Sans ce + 26, déchiffrer
une lettre dont l’index est inférieur au décalage donnerait un index négatif, donc
undefined dans le tableau.
newMessage.join("") : on accumule dans un tableau et on assemble à la fin. Concaténer
avec += dans une boucle fonctionne, mais un tableau + .join() est plus propre — et plus
performant sur de longs messages.
Côté input, le message et la clé passent par une normalisation avant d’entrer dans la fonction :
const message = messageDiv.value
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.toUpperCase()
.split("")
const key = keyDiv.value
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.toUpperCase()
.split("")
.filter(c => FR_ALPHABET.indexOf(c) !== -1)
Le .normalize("NFD").replace(/[\u0300-\u036f]/g, "") supprime les accents — é devient
E, à devient A. Pas parfait sémantiquement, mais ça permet de traiter du texte français
sans sortir des 26 lettres. La clé est filtrée en plus pour ignorer silencieusement tout
caractère non alphabétique plutôt que de provoquer un comportement inattendu.
Le résultat est dispo ici : Encode Loader.
Ce que j’en retiens
Je ne cherchais rien. Je me baladais. Et j’ai fini avec un projet qui tourne, une compréhension concrète d’un algorithme vieux de plusieurs siècles, et une particularité de JavaScript héritée des langages bas niveau qui, franchement, aide beaucoup.
C’est ça que j’aime dans ce genre de curiosité sans but précis. On n’est pas sous pression, on écoute de la musique tranquillement. On explore. Et parfois on tombe sur des trucs qui nous rappellent pourquoi on aime coder
Le plaisir avant tout
On parle beaucoup de se former, de monter en compétences, d’être à jour sur les technos. C’est légitime. Mais je pense qu’on oublie parfois un truc simple : coder doit rester quelque chose qu’on aime faire.
Pas besoin que chaque projet serve à quelque chose. Pas besoin que ça finisse sur un CV. Certains des trucs les plus intéressants que j’ai appris venaient de projets complètement inutiles, faits un soir sans raison précise.
Si tu ne prends plus de plaisir à coder, ne te force pas pas à produire. Reprends une curiosité au hasard. Ouvre Wikipedia. Implémente un truc bizarre. Rappelle-toi pourquoi t’as commencé.